Skip to content

Commit d59bdd9

Browse files
authored
VB support for back-end and add IOperation as part of node properties (#14)
* Initial re-organization * One more step * Add IOperation to properties * Add back-end support for VB
1 parent 1f0c068 commit d59bdd9

File tree

4 files changed

+71
-53
lines changed

4 files changed

+71
-53
lines changed

DotNetSyntaxTreeVisualizer/ClientApp/src/components/Home.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export class Home extends Component {
3737
headers: { 'Content-Type': 'text/plain;charset=UTF-8' },
3838
body: event.target.value
3939
};
40-
fetch('SyntaxTree', requestOptions)
40+
fetch('SyntaxTree/CSharp', requestOptions)
4141
.then(response => response.json())
4242
.then(data => this.setState({ treeJson: data }));
4343
}

DotNetSyntaxTreeVisualizer/Controllers/SyntaxTreeController.cs

Lines changed: 17 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.AspNetCore.Mvc;
99
using Microsoft.CodeAnalysis;
1010
using Microsoft.CodeAnalysis.CSharp;
11+
using Microsoft.CodeAnalysis.VisualBasic;
1112
using Microsoft.Extensions.Logging;
1213

1314
namespace DotNetSyntaxTreeVisualizer.Controllers
@@ -23,65 +24,30 @@ public SyntaxTreeController(ILogger<SyntaxTreeController> logger)
2324
_logger = logger;
2425
}
2526

26-
[HttpPost]
27+
[HttpPost("CSharp")] // POST: /SyntaxTree/CSharp
2728
public async Task<SyntaxTreeNode> CSharpPost(CancellationToken cancellationToken)
2829
{
2930
using var reader = new StreamReader(Request.Body, Encoding.UTF8);
3031
string body = await reader.ReadToEndAsync().ConfigureAwait(false);
31-
SyntaxNode root = await CSharpSyntaxTree.ParseText(body).GetRootAsync(cancellationToken).ConfigureAwait(false);
32-
SyntaxTreeNode myRoot = CreateMyOwnTree(root);
32+
SyntaxTree tree = CSharpSyntaxTree.ParseText(body);
33+
SyntaxNode root = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false);
34+
Compilation compilation = CSharpCompilation.Create("HelloWorld", new[] { tree });
35+
SemanticModel model = compilation.GetSemanticModel(tree);
36+
SyntaxTreeNode myRoot = SyntaxTreeNode.CreateMyOwnTree(root, model);
3337
return myRoot;
3438
}
3539

36-
private SyntaxTreeNode CreateMyOwnTree(SyntaxNodeOrToken nodeOrToken)
40+
[HttpPost("VisualBasic")] // POST: /SyntaxTree/VisualBasic
41+
public async Task<SyntaxTreeNode> VisualBasicPost(CancellationToken cancellationToken)
3742
{
38-
var root = new SyntaxTreeNode(GetSyntaxNodeOrTokenInformation(nodeOrToken));
39-
foreach (SyntaxNodeOrToken child in nodeOrToken.ChildNodesAndTokens())
40-
{
41-
root.AddChild(CreateMyOwnTree(child));
42-
}
43-
return root;
44-
}
45-
46-
private IDictionary<string, string> GetSyntaxNodeOrTokenInformation(SyntaxNodeOrToken nodeOrToken)
47-
{
48-
return nodeOrToken.IsNode
49-
? GetSyntaxInformation(nodeOrToken.AsNode())
50-
: GetSyntaxInformation(nodeOrToken.AsToken());
51-
}
52-
53-
private IDictionary<string, string> GetSyntaxInformation<T>(T syntax)
54-
{
55-
var result = new Dictionary<string, string>();
56-
if (syntax is SyntaxNode node)
57-
{
58-
result.Add("NodeKind", node.Kind().ToString()); // TODO: Kind() here is for C#. Considering fixing that.
59-
}
60-
else if (syntax is SyntaxToken token)
61-
{
62-
result.Add("TokenKind", token.Kind().ToString());
63-
}
64-
else
65-
{
66-
throw new ArgumentException($"The specified {nameof(syntax)} is not a SyntaxNode nor a SyntaxToken.");
67-
}
68-
PropertyInfo[] properties = syntax.GetType().GetProperties();
69-
foreach (PropertyInfo info in properties)
70-
{
71-
// Language isn't important to include in each node.
72-
// Parent is redundant. I can already see the parent.
73-
// ValueText and Value are the same as Text.
74-
// SyntaxTree shows the complete source in each node. That's redundant.
75-
// RawKind is just the underlying numeric value of SyntaxKind enum. It's meaningless.
76-
if (info.Name == "Language" || info.Name == "Parent" ||
77-
info.Name == "ValueText" || info.Name == "Value" ||
78-
info.Name == "SyntaxTree" || info.Name == "RawKind")
79-
{
80-
continue;
81-
}
82-
result.Add(info.Name, info.GetValue(syntax)?.ToString());
83-
}
84-
return result;
43+
using var reader = new StreamReader(Request.Body, Encoding.UTF8);
44+
string body = await reader.ReadToEndAsync().ConfigureAwait(false);
45+
SyntaxTree tree = VisualBasicSyntaxTree.ParseText(body);
46+
SyntaxNode root = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false);
47+
Compilation compilation = VisualBasicCompilation.Create("HelloWorld", new[] { tree });
48+
SemanticModel model = compilation.GetSemanticModel(tree);
49+
SyntaxTreeNode myRoot = SyntaxTreeNode.CreateMyOwnTree(root, model);
50+
return myRoot;
8551
}
8652
}
8753
}

DotNetSyntaxTreeVisualizer/DotNetSyntaxTreeVisualizer.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111

1212
<ItemGroup>
1313
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="3.1.4" />
14-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.6.0" />
14+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.7.0" />
15+
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="3.7.0" />
1516
</ItemGroup>
1617

1718
<ItemGroup>

DotNetSyntaxTreeVisualizer/SyntaxTreeNode.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Reflection;
5+
using Microsoft.CodeAnalysis;
46

57
namespace DotNetSyntaxTreeVisualizer
68
{
@@ -20,6 +22,55 @@ public void AddChild(SyntaxTreeNode child)
2022
Children.Add(child);
2123
}
2224

25+
public static SyntaxTreeNode CreateMyOwnTree(SyntaxNodeOrToken nodeOrToken, SemanticModel model)
26+
{
27+
var root = new SyntaxTreeNode(GetSyntaxInformation(nodeOrToken, model));
28+
foreach (SyntaxNodeOrToken child in nodeOrToken.ChildNodesAndTokens())
29+
{
30+
root.AddChild(CreateMyOwnTree(child, model));
31+
}
32+
return root;
33+
}
34+
35+
private static IDictionary<string, string> GetSyntaxInformation(SyntaxNodeOrToken syntax, SemanticModel model)
36+
{
37+
Func<SyntaxNodeOrToken, Microsoft.CodeAnalysis.CSharp.SyntaxKind> csharpKind = Microsoft.CodeAnalysis.CSharp.CSharpExtensions.Kind;
38+
Func<SyntaxNodeOrToken, Microsoft.CodeAnalysis.VisualBasic.SyntaxKind> vbKind = Microsoft.CodeAnalysis.VisualBasic.VisualBasicExtensions.Kind;
39+
string kind =
40+
syntax.Language == LanguageNames.CSharp
41+
? csharpKind(syntax).ToString()
42+
: vbKind(syntax).ToString();
43+
44+
var result = new Dictionary<string, string>
45+
{
46+
{ "Kind", kind },
47+
};
48+
49+
IOperation operation = model.GetOperation(syntax.AsNode());
50+
if (operation is object)
51+
{
52+
result.Add(nameof(IOperation), operation.Kind.ToString());
53+
}
54+
55+
PropertyInfo[] properties = syntax.GetType().GetProperties();
56+
foreach (PropertyInfo info in properties)
57+
{
58+
// Language isn't important to include in each node.
59+
// Parent is redundant. I can already see the parent.
60+
// ValueText and Value are the same as Text.
61+
// SyntaxTree shows the complete source in each node. That's redundant.
62+
// RawKind is just the underlying numeric value of SyntaxKind enum. It's meaningless.
63+
if (info.Name == "Language" || info.Name == "Parent" ||
64+
info.Name == "ValueText" || info.Name == "Value" ||
65+
info.Name == "SyntaxTree" || info.Name == "RawKind")
66+
{
67+
continue;
68+
}
69+
result.Add(info.Name, info.GetValue(syntax)?.ToString());
70+
}
71+
return result;
72+
}
73+
2374
public override string ToString()
2475
{
2576
return Properties.Values.First();

0 commit comments

Comments
 (0)