diff --git a/Shared/CSharpBlockMetadata.cs b/Shared/CSharpBlockMetadata.cs
new file mode 100644
index 0000000..9b32582
--- /dev/null
+++ b/Shared/CSharpBlockMetadata.cs
@@ -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;
+ // }
+ //}
+}
diff --git a/Shared/CSharpCodeWriter.cs b/Shared/CSharpCodeWriter.cs
index afb1d3e..4950d41 100644
--- a/Shared/CSharpCodeWriter.cs
+++ b/Shared/CSharpCodeWriter.cs
@@ -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 {
@@ -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) {
@@ -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("}");
+ }
}
}
@@ -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 _:
@@ -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();
@@ -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);
@@ -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("}");
}
@@ -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) => {
@@ -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("}");
}
@@ -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("}");
}
@@ -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("}");
}
diff --git a/Shared/CSharpMultilineBlockTypes.cs b/Shared/CSharpMultilineBlockTypes.cs
new file mode 100644
index 0000000..bf98a55
--- /dev/null
+++ b/Shared/CSharpMultilineBlockTypes.cs
@@ -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
+ }
+}
diff --git a/Shared/FactoryMethodsFormatter.cs b/Shared/FactoryMethodsFormatter.cs
index f90b6ab..28c0525 100644
--- a/Shared/FactoryMethodsFormatter.cs
+++ b/Shared/FactoryMethodsFormatter.cs
@@ -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()));
diff --git a/Shared/Shared.projitems b/Shared/Shared.projitems
index 127a230..a755642 100644
--- a/Shared/Shared.projitems
+++ b/Shared/Shared.projitems
@@ -9,10 +9,14 @@
ExpressionToString
+
+
+
+
diff --git a/Shared/Util/Extensions/BlockExpression.cs b/Shared/Util/Extensions/BlockExpression.cs
new file mode 100644
index 0000000..a3f7041
--- /dev/null
+++ b/Shared/Util/Extensions/BlockExpression.cs
@@ -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;
+ }
+}
diff --git a/Shared/VBBlockMetadata.cs b/Shared/VBBlockMetadata.cs
new file mode 100644
index 0000000..9e80c20
--- /dev/null
+++ b/Shared/VBBlockMetadata.cs
@@ -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
+ };
+ }
+}
diff --git a/Shared/VBCodeWriter.cs b/Shared/VBCodeWriter.cs
index bf922c8..3cd082e 100644
--- a/Shared/VBCodeWriter.cs
+++ b/Shared/VBCodeWriter.cs
@@ -12,6 +12,7 @@
using static System.Linq.Expressions.ExpressionType;
using static System.Linq.Expressions.GotoExpressionKind;
using static ExpressionToString.Util.Methods;
+using static ExpressionToString.VBBlockMetadata;
namespace ExpressionToString {
public class VBCodeWriter : WriterBase {
@@ -253,18 +254,26 @@ protected override void WriteUnary(UnaryExpression expr) =>
WriteUnary(expr.NodeType, "Operand", expr.Operand, expr.Type, expr.GetType().Name);
protected override void WriteLambda(LambdaExpression expr) {
- if (expr.ReturnType == typeof(void)) {
- Write("Sub");
- } else {
- Write("Function");
- }
- Write("(");
+ var lambdaKeyword = expr.ReturnType == typeof(void) ? "Sub" : "Function";
+ Write($"{lambdaKeyword}(");
expr.Parameters.ForEach((prm, index) => {
if (index > 0) { Write(", "); }
WriteNode($"Parameters[{index}]", prm, true);
});
- Write(") ");
- WriteNode("Body", expr.Body);
+ Write(")");
+
+ if (CanInline(expr.Body)) {
+ Write(" ");
+ WriteNode("Body", expr.Body);
+ return;
+ }
+
+ Indent();
+ WriteEOL();
+ if (expr.Body.Type != typeof(void)) { Write("Return "); }
+ WriteNode("Body", expr.Body, CreateMetadata(true,false));
+ WriteEOL(true);
+ Write($"End {lambdaKeyword}");
}
protected override void WriteParameterDeclarationImpl(ParameterExpression prm) {
@@ -541,49 +550,56 @@ protected override void WriteNewArray(NewArrayExpression expr) {
}
}
- private bool IndentIfBlockSyntax(string path, Expression expr, (bool leading, bool trailing) nonblockSpaces, bool? explicitBlock = false) {
- if (IsBlockSyntax(expr)) {
- if (explicitBlock ?? false) {
- WriteNode(path, expr, false, true);
- } else {
- Indent();
- WriteEOL();
- WriteNode(path, expr, false, explicitBlock);
- WriteEOL(true);
- }
- return true;
- } else {
- if (nonblockSpaces.leading) { Write(" "); }
- WriteNode(path, expr);
- if (nonblockSpaces.trailing) { Write(" "); }
- return false;
- }
- }
-
protected override void WriteConditional(ConditionalExpression expr) {
- if (expr.Type == typeof(void)) {
- var lastClauseIsBlock = false;
- Write("If");
- IndentIfBlockSyntax("Test", expr.Test, (true, true));
- Write("Then");
- lastClauseIsBlock = IsBlockSyntax(expr.IfTrue);
- IndentIfBlockSyntax("IfTrue", expr.IfTrue, (true, !expr.IfFalse.IsEmpty()));
- if (!expr.IfFalse.IsEmpty()) {
- Write("Else");
- lastClauseIsBlock = IndentIfBlockSyntax("IfFalse", expr.IfFalse, (true, false));
- }
- if (lastClauseIsBlock) {
- Write("End If");
- }
- } else {
+ if (expr.Type != typeof(void)) {
Write("If(");
- IndentIfBlockSyntax("Test", expr.Test, (false, false), true);
+ WriteNode("Test", expr.Test);
Write(", ");
WriteNode("IfTrue", expr.IfTrue);
Write(", ");
WriteNode("IfFalse", expr.IfFalse);
Write(")");
+ return;
}
+
+ var metadata = CreateMetadata(true, false);
+
+ if (CanInline(expr.Test)) {
+ Write("If ");
+ WriteNode("Test", expr.Test);
+ Write(" Then");
+ } else {
+ Write("If");
+ Indent();
+ WriteEOL();
+ WriteNode("Test", expr.Test, metadata);
+ WriteEOL(true);
+ Write("Then");
+ }
+
+ var canInline = new[] { expr.IfTrue, expr.IfFalse }.All(x => CanInline(x));
+ if (canInline) {
+ Write(" ");
+ WriteNode("IfTrue", expr.IfTrue);
+ if (!expr.IfFalse.IsEmpty()) {
+ Write(" Else ");
+ WriteNode("IfFalse", expr.IfFalse);
+ }
+ return;
+ }
+
+ Indent();
+ WriteEOL();
+ WriteNode("IfTrue", expr.IfTrue, metadata);
+ WriteEOL(true);
+ if (!expr.IfFalse.IsEmpty()) {
+ Write("Else");
+ Indent();
+ WriteEOL();
+ WriteNode("IfFalse", expr.IfFalse, metadata);
+ WriteEOL(true);
+ }
+ Write("End If");
}
protected override void WriteDefault(DefaultExpression expr) =>
@@ -615,39 +631,45 @@ 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 = null) {
- var useExplicitBlock = explicitBlock ?? expr.Variables.Count > 0;
- if (useExplicitBlock) {
+ protected override void WriteBlock(BlockExpression expr, object metadata) {
+ var blockMetedata = metadata as VBBlockMetadata ?? CreateMetadata(false, false);
+ var useBlockConstruct = !blockMetedata.IsInMutiline || (expr.Variables.Any() && blockMetedata.ParentIsBlock);
+ if (useBlockConstruct) {
Write("Block");
Indent();
WriteEOL();
- expr.Variables.ForEach((v, index) => {
- if (index > 0) { WriteEOL(); }
- Write("Dim ");
- WriteNode($"Variables[{index}]", v, true);
- });
}
+ expr.Variables.ForEach((v, index) => {
+ if (index > 0) { WriteEOL(); }
+ Write("Dim ");
+ WriteNode($"Variables[{index}]", v, true);
+ });
expr.Expressions.ForEach((subexpr, index) => {
if (index > 0 || expr.Variables.Count > 0) { WriteEOL(); }
if (subexpr is LabelExpression) { TrimEnd(); }
- WriteNode($"Expressions[{index}]", subexpr);
+ WriteNode($"Expressions[{index}]", subexpr, CreateMetadata(true, true));
});
- if (useExplicitBlock) {
+ if (useBlockConstruct) {
WriteEOL(true);
Write("End Block");
}
}
- private bool IsBlockSyntax(Expression expr) {
+ private bool CanInline(Expression expr) {
switch (expr) {
case ConditionalExpression cexpr when cexpr.Type == typeof(void):
- case BlockExpression _:
+ 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 _:
- return true;
+ throw new NotImplementedException();
}
- return false;
+ return true;
}
protected override void WriteSwitchCase(SwitchCase switchCase) {
@@ -655,25 +677,22 @@ protected override void WriteSwitchCase(SwitchCase switchCase) {
WriteNodes("TestValues", switchCase.TestValues);
Indent();
WriteEOL();
- WriteNode("Body", switchCase.Body);
+ WriteNode("Body", switchCase.Body, CreateMetadata(true, false));
+ Dedent();
}
protected override void WriteSwitch(SwitchExpression expr) {
Write("Select Case ");
Indent();
- WriteNode("SwitchValue", expr.SwitchValue, false, true);
+ WriteNode("SwitchValue", expr.SwitchValue);
WriteEOL();
- expr.Cases.ForEach((switchCase, index) => {
- if (index > 0) { WriteEOL(); }
- WriteNode($"Cases[{index}]", switchCase);
- Dedent();
- });
+ WriteNodes("Cases", expr.Cases, true, "");
if (expr.DefaultBody != null) {
if (expr.Cases.Count > 0) { WriteEOL(); }
Write("Case Else");
Indent();
WriteEOL();
- WriteNode("DefaultBody", expr.DefaultBody);
+ WriteNode("DefaultBody", expr.DefaultBody, CreateMetadata(true, false));
Dedent();
}
WriteEOL(true);
@@ -690,18 +709,18 @@ protected override void WriteCatchBlock(CatchBlock catchBlock) {
}
if (catchBlock.Filter != null) {
Write(" When ");
- WriteNode("Filter", catchBlock.Filter, false, true);
+ WriteNode("Filter", catchBlock.Filter);
}
Indent();
WriteEOL();
- WriteNode("Body", catchBlock.Body);
+ WriteNode("Body", catchBlock.Body, CreateMetadata(true, false));
}
protected override void WriteTry(TryExpression expr) {
Write("Try");
Indent();
WriteEOL();
- WriteNode("Body", expr.Body, false, false);
+ WriteNode("Body", expr.Body, CreateMetadata(true, false));
WriteEOL(true);
expr.Handlers.ForEach((catchBlock, index) => {
WriteNode($"Handlers[{index}]", catchBlock);
@@ -711,14 +730,14 @@ protected override void WriteTry(TryExpression expr) {
Write("Fault");
Indent();
WriteEOL();
- WriteNode("Fault", expr.Fault, false, false);
+ WriteNode("Fault", expr.Fault, CreateMetadata(true, false));
WriteEOL(true);
}
if (expr.Finally != null) {
Write("Finally");
Indent();
WriteEOL();
- WriteNode("Finally", expr.Finally, false, false);
+ WriteNode("Finally", expr.Finally, CreateMetadata(true, false));
WriteEOL(true);
}
Write("End Try");
@@ -764,7 +783,7 @@ protected override void WriteLoop(LoopExpression expr) {
Write("Do");
Indent();
WriteEOL();
- WriteNode("Body", expr.Body);
+ WriteNode("Body", expr.Body, CreateMetadata(true, false));
WriteEOL(true);
Write("Loop");
}
@@ -833,7 +852,7 @@ protected override void WriteInvokeMemberBinder(InvokeMemberBinder binder, IList
VerifyCount(args, 1, null);
WriteNode("Arguments[0]", args[0]);
Write($".{binder.Name}");
- if (args.Count>1) {
+ if (args.Count > 1) {
Write("(");
WriteNodes(args.Skip(1).Select((arg, index) => ($"Arguments[{index + 1}]", arg)));
Write(")");
diff --git a/Shared/WriterBase.cs b/Shared/WriterBase.cs
index 06235c4..2d6a437 100644
--- a/Shared/WriterBase.cs
+++ b/Shared/WriterBase.cs
@@ -63,8 +63,9 @@ protected virtual void PreWrite() { }
/// Write a string-rendering of an expression or other type used in expression trees
/// Object to be rendered
/// For ParameterExpression, this is a parameter declaration
- /// For BlockExpression, controls explicit block rendering: true forces the rendering; false prevents the rendering; and null determines automatically
- protected void WriteNode(string pathSegment, object o, bool parameterDeclaration = false, bool? explicitBlock = null) {
+ /// For BlockExpression, sets the preferred block type
+ ///
+ protected void WriteNode(string pathSegment, object o, bool parameterDeclaration = false, object blockMetadata = null) {
if (!pathSegment.IsNullOrWhitespace()) { pathSegments.Add(pathSegment); }
var start = sb.Length;
try {
@@ -72,8 +73,8 @@ protected void WriteNode(string pathSegment, object o, bool parameterDeclaration
case ParameterExpression pexpr when parameterDeclaration:
WriteParameterDeclarationImpl(pexpr);
break;
- case BlockExpression bexpr when explicitBlock != null:
- WriteBlock(bexpr, explicitBlock);
+ case BlockExpression bexpr when blockMetadata != null:
+ WriteBlock(bexpr, blockMetadata);
break;
case Expression expr:
WriteExpression(expr);
@@ -111,6 +112,7 @@ protected void WriteNode(string pathSegment, object o, bool parameterDeclaration
}
}
protected void WriteNode((string pathSegment, object o) x) => WriteNode(x.pathSegment, x.o);
+ protected void WriteNode(string pathSegment, object o, object blockMetadata) => WriteNode(pathSegment, o, false, blockMetadata);
private readonly HashSet binaryExpressionTypes = new[] {
Add, AddChecked, Divide, Modulo, Multiply, MultiplyChecked, Power, Subtract, SubtractChecked, // mathematical operators
@@ -204,7 +206,7 @@ private void WriteExpression(Expression expr) {
break;
case Block:
- WriteBlock(expr as BlockExpression);
+ WriteBlock(expr as BlockExpression, null);
break;
case Switch:
@@ -304,7 +306,8 @@ protected void WriteNodes(IEnumerable<(string pathSegment, T o)> pathsItems,
protected void WriteNodes(string pathSegment, IEnumerable items, bool writeEOL, string delimiter = ", ", bool parameterDeclaration = false) =>
WriteNodes(items.Select((arg, index) => ($"{pathSegment}[{index}]", arg)), writeEOL, delimiter, parameterDeclaration);
- protected void WriteNodes(string pathSegment, IEnumerable items, string delimiter = ", ") => WriteNodes(pathSegment, items, false, delimiter);
+ protected void WriteNodes(string pathSegment, IEnumerable items, string delimiter = ", ", bool parameterDeclaration=false) =>
+ WriteNodes(pathSegment, items, false, delimiter, parameterDeclaration);
protected void TrimEnd(bool trimEOL = false) => sb.TrimEnd(trimEOL);
@@ -329,7 +332,7 @@ protected void WriteNodes(string pathSegment, IEnumerable items, bool writ
protected abstract void WriteIndex(IndexExpression expr);
// .NET 4 expression types
- protected abstract void WriteBlock(BlockExpression expr, bool? explicitBlock = null);
+ protected abstract void WriteBlock(BlockExpression expr, object metadata);
protected abstract void WriteSwitch(SwitchExpression expr);
protected abstract void WriteTry(TryExpression expr);
protected abstract void WriteLabel(LabelExpression expr);
diff --git a/Tests.Common/Constructed/MakeBlock.cs b/Tests.Common/Constructed/MakeBlock.cs
index 96a2c3c..500c503 100644
--- a/Tests.Common/Constructed/MakeBlock.cs
+++ b/Tests.Common/Constructed/MakeBlock.cs
@@ -13,10 +13,14 @@ public void BlockNoVariables() => RunTest(
Constant(true),
Constant(true)
),
- @"true;
-true;",
- @"True
-True",
+ @"(
+ true,
+ true
+)",
+ @"Block
+ True
+ True
+End Block",
@"Block(
Constant(true),
Constant(true)
@@ -31,11 +35,11 @@ public void BlockSingleVariable() => RunTest(
Constant(true),
Constant(true)
),
- @"{
- int i;
- true;
- true;
-}",
+ @"(
+ int i,
+ true,
+ true
+)",
@"Block
Dim i As Integer
True
@@ -55,12 +59,12 @@ public void BlockMultipleVariable() => RunTest(
Constant(true),
Constant(true)
),
- @"{
- int i;
- string s1;
- true;
- true;
-}",
+ @"(
+ int i,
+ string s1,
+ true,
+ true
+)",
@"Block
Dim i As Integer
Dim s1 As String
diff --git a/Tests.Common/Constructed/MakeConditional.cs b/Tests.Common/Constructed/MakeConditional.cs
index 5661121..aa32b29 100644
--- a/Tests.Common/Constructed/MakeConditional.cs
+++ b/Tests.Common/Constructed/MakeConditional.cs
@@ -18,7 +18,11 @@ public void VoidConditionalWithElse() => RunTest(
writeLineTrue,
writeLineFalse
),
- "if (true) Console.WriteLine(true); else Console.WriteLine(false);",
+ @"if (true) {
+ Console.WriteLine(true);
+} else {
+ Console.WriteLine(false);
+}",
"If True Then Console.WriteLine(True) Else Console.WriteLine(False)",
@"IfThenElse(
Constant(true),
@@ -41,7 +45,11 @@ public void VoidConditional1WithElse() => RunTest(
writeLineTrue,
writeLineFalse
),
- @"if (true) Console.WriteLine(true); else Console.WriteLine(false);",
+ @"if (true) {
+ Console.WriteLine(true);
+} else {
+ Console.WriteLine(false);
+}",
@"If True Then Console.WriteLine(True) Else Console.WriteLine(False)",
@"IfThenElse(
Constant(true),
@@ -64,7 +72,9 @@ public void VoidConditionalWithoutElse() => RunTest(
writeLineTrue,
Empty()
),
- "if (true) Console.WriteLine(true);",
+ @"if (true) {
+ Console.WriteLine(true);
+}",
"If True Then Console.WriteLine(True)",
@"IfThen(
Constant(true),
@@ -82,7 +92,9 @@ public void VoidConditional1WithoutElse() => RunTest(
Constant(true),
writeLineTrue
),
- "if (true) Console.WriteLine(true);",
+ @"if (true) {
+ Console.WriteLine(true);
+}",
"If True Then Console.WriteLine(True)",
@"IfThen(
Constant(true),
@@ -146,10 +158,10 @@ public void MultilineTestPart() => RunTest(
trueLength,
falseLength
),
- @"{
- true;
- true;
-} ? ""true"".Length : ""false"".Length",
+ @"(
+ true,
+ true
+) ? ""true"".Length : ""false"".Length",
@"If(Block
True
True
@@ -177,10 +189,12 @@ public void MultilineTestPart1() => RunTest(
Block(Constant(true), Constant(true)),
writeLineTrue
),
- @"if ({
- true;
- true;
-}) Console.WriteLine(true);",
+ @"if (
+ true,
+ true
+) {
+ Console.WriteLine(true);
+}",
@"If
True
True
@@ -237,7 +251,11 @@ public void NestedIfThen() => RunTest(
writeLineTrue
)
),
- @"if (true) if (true) Console.WriteLine(true);",
+ @"if (true) {
+ if (true) {
+ Console.WriteLine(true);
+ }
+}",
@"If True Then
If True Then Console.WriteLine(True)
End If",
@@ -253,6 +271,7 @@ If True Then Console.WriteLine(True)
)"
);
+ // TODO nested ifs look strange in VB.NET
[Fact]
[Trait("Category", Conditionals)]
public void NestedElse() => RunTest(
@@ -264,8 +283,14 @@ public void NestedElse() => RunTest(
writeLineTrue
)
),
- @"if (true) Console.WriteLine(true); else if (true) Console.WriteLine(true);",
- @"If True Then Console.WriteLine(True) Else
+ @"if (true) {
+ Console.WriteLine(true);
+} else if (true) {
+ Console.WriteLine(true);
+}",
+ @"If True Then
+ Console.WriteLine(True)
+Else
If True Then Console.WriteLine(True)
End If",
@"IfThenElse(
diff --git a/Tests.Common/Constructed/MakeLabel.cs b/Tests.Common/Constructed/MakeLabel.cs
index 10bd296..d53b441 100644
--- a/Tests.Common/Constructed/MakeLabel.cs
+++ b/Tests.Common/Constructed/MakeLabel.cs
@@ -19,15 +19,15 @@ public void ConstructLabel() => RunTest(
Constant(true)
)
),
- @"{
- int i;
- {
- int j;
- true;
+ @"(
+ int i,
+ (
+ int j,
+ true,
target:
- true;
- }
-}",
+ true
+ )
+)",
@"Block
Dim i As Integer
Block
@@ -60,14 +60,14 @@ public void ConstructLabel1() => RunTest(
Constant(true)
)
),
- @"{
- int i;
- {
- int j;
+ @"(
+ int i,
+ (
+ int j,
target:
- true;
- }
-}",
+ true
+ )
+)",
@"Block
Dim i As Integer
Block
diff --git a/Tests.Common/Constructed/MakeLambda.cs b/Tests.Common/Constructed/MakeLambda.cs
index 3dbefe5..cee1bfe 100644
--- a/Tests.Common/Constructed/MakeLambda.cs
+++ b/Tests.Common/Constructed/MakeLambda.cs
@@ -8,9 +8,9 @@ public partial class ConstructedBase {
[Fact]
[Trait("Category", Lambdas)]
public void NoParametersVoidReturn() => RunTest(
- Lambda(Call(writeline0)),
- "() => Console.WriteLine()",
- "Sub() Console.WriteLine",
+ Lambda(Call(writeline0)),
+ "() => Console.WriteLine()",
+ "Sub() Console.WriteLine",
@"Lambda(
Call(
typeof(Console).GetMethod(""WriteLine"")
@@ -21,9 +21,9 @@ public void NoParametersVoidReturn() => RunTest(
[Fact]
[Trait("Category", Lambdas)]
public void OneParameterVoidReturn() => RunTest(
- Lambda(Call(writeline1, s), s),
- "(string s) => Console.WriteLine(s)",
- "Sub(s As String) Console.WriteLine(s)",
+ Lambda(Call(writeline1, s), s),
+ "(string s) => Console.WriteLine(s)",
+ "Sub(s As String) Console.WriteLine(s)",
@"Lambda(
Call(
typeof(Console).GetMethod(""WriteLine""),
@@ -41,7 +41,7 @@ public void OneParameterVoidReturn() => RunTest(
public void TwoParametersVoidReturn() => RunTest(
Lambda(Call(writeline1, Add(s1, s2, concat)), s1, s2),
"(string s1, string s2) => Console.WriteLine(s1 + s2)",
- "Sub(s1 As String, s2 As String) Console.WriteLine(s1 + s2)",
+ "Sub(s1 As String, s2 As String) Console.WriteLine(s1 + s2)",
@"Lambda(
Call(
typeof(Console).GetMethod(""WriteLine""),
@@ -63,7 +63,7 @@ public void TwoParametersVoidReturn() => RunTest(
public void NoParametersNonVoidReturn() => RunTest(
Lambda(Constant("abcd")),
"() => \"abcd\"",
- "Function() \"abcd\"",
+ "Function() \"abcd\"",
@"Lambda(
Constant(""abcd"")
)"
@@ -74,7 +74,7 @@ public void NoParametersNonVoidReturn() => RunTest(
public void OneParameterNonVoidReturn() => RunTest(
Lambda(s, s),
"(string s) => s",
- "Function(s As String) s",
+ "Function(s As String) s",
@"Lambda(s,
var s = Parameter(
typeof(string),
@@ -105,7 +105,11 @@ public void TwoParametersNonVoidReturn() => RunTest(
[Fact]
[Trait("Category", Lambdas)]
public void NamedLambda() => RunTest(
- Lambda(Add(s1, s2, concat), "name", new [] { s1, s2 }),
+ Lambda(
+ Add(s1, s2, concat),
+ "name",
+ new[] { s1, s2 }
+ ),
"(string s1, string s2) => s1 + s2",
"Function(s1 As String, s2 As String) s1 + s2",
@"Lambda(
@@ -120,6 +124,58 @@ public void NamedLambda() => RunTest(
""s2""
)
}
+)"
+ );
+
+ [Fact]
+ [Trait("Category", Lambdas)]
+ public void MultilineLambda() => RunTest(
+ Lambda(
+ IfThen(Constant(true), writeLineTrue)
+ ),
+ @"() => {
+ if (true) {
+ Console.WriteLine(true);
+ }
+}",
+ @"Sub()
+ If True Then Console.WriteLine(True)
+End Sub",
+ @"Lambda(
+ IfThen(
+ Constant(true),
+ Call(
+ typeof(Console).GetMethod(""WriteLine""),
+ Constant(true)
+ )
+ )
+)"
+ );
+
+ [Fact]
+ [Trait("Category", Lambdas)]
+ public void NestedLambda() => RunTest(
+ Lambda(
+ Lambda(Add(s1, s2, concat), s1, s2)
+ ),
+ @"() => {
+ return (string s1, string s2) => s1 + s2;
+}",
+ @"Function()
+ Return Function(s1 As String, s2 As String) s1 + s2
+End Function",
+ @"Lambda(
+ Lambda(
+ Add(s1, s2),
+ var s1 = Parameter(
+ typeof(string),
+ ""s1""
+ ),
+ var s2 = Parameter(
+ typeof(string),
+ ""s2""
+ )
+ )
)"
);
}
diff --git a/Tests.Common/Constructed/MakeRuntimeVariables.cs b/Tests.Common/Constructed/MakeRuntimeVariables.cs
index 8f87d80..82a4070 100644
--- a/Tests.Common/Constructed/MakeRuntimeVariables.cs
+++ b/Tests.Common/Constructed/MakeRuntimeVariables.cs
@@ -22,11 +22,11 @@ public void RuntimeVariablesWithinBlock() => RunTest(
Constant(true),
RuntimeVariables(x, s1)
),
- @"{
- string s2;
- true;
+ @"(
+ string s2,
+ true
// variables -- double x, string s1
-}",
+)",
@"Block
Dim s2 As String
True
diff --git a/Tests.Common/Constructed/MakeSwitch.cs b/Tests.Common/Constructed/MakeSwitch.cs
index 81c9b6c..fde485a 100644
--- a/Tests.Common/Constructed/MakeSwitch.cs
+++ b/Tests.Common/Constructed/MakeSwitch.cs
@@ -229,10 +229,10 @@ public void SwitchOnMultipleStatementsWithDefault() => RunTest(
Constant(5)
)
),
- @"switch ({
- i;
- j;
-}) {
+ @"switch (
+ i,
+ j
+) {
case 4:
Console.WriteLine(true);
break;
@@ -331,10 +331,10 @@ public void SwitchOnMultipleStatementsWithoutDefault() => RunTest(
Constant(5)
)
),
- @"switch ({
- i;
- j;
-}) {
+ @"switch (
+ i,
+ j
+) {
case 4:
Console.WriteLine(true);
break;
diff --git a/Tests.Common/Constructed/MakeTry.cs b/Tests.Common/Constructed/MakeTry.cs
index ad45de9..73806e3 100644
--- a/Tests.Common/Constructed/MakeTry.cs
+++ b/Tests.Common/Constructed/MakeTry.cs
@@ -162,10 +162,10 @@ public void ConstructCatchMultiStatementWithFilter() => RunTest(
[Trait("Category", Try)]
public void ConstructCatchWithMultiStatementFilter() => RunTest(
Catch(ex, writeLineTrue, Block(Constant(true), Constant(true))),
- @"catch (Exception ex) when ({
- true;
- true;
-}) {
+ @"catch (Exception ex) when (
+ true,
+ true
+) {
Console.WriteLine(true);
}",
@"Catch ex As Exception When Block
diff --git a/Tests.Common/Constructed/Misc.cs b/Tests.Common/Constructed/Misc.cs
index d46dec0..c662f0e 100644
--- a/Tests.Common/Constructed/Misc.cs
+++ b/Tests.Common/Constructed/Misc.cs
@@ -99,12 +99,12 @@ public void MakeQuoted() => RunTest(
Lambda(writeLineTrue)
)
),
- @"{
- double x;
+ @"(
+ double x,
// --- Quoted - begin
() => Console.WriteLine(true)
// --- Quoted - end
-}",
+)",
@"Block
Dim x As Double
' --- Quoted - begin