diff options
| author | Victoria Plitt <Victoria.Plitt@twine-s.com> | 2019-04-08 13:49:55 +0300 |
|---|---|---|
| committer | Victoria Plitt <Victoria.Plitt@twine-s.com> | 2019-04-08 13:49:55 +0300 |
| commit | fc8a05358a92cc3c77c5f1e30d536807ef0614fd (patch) | |
| tree | c65f696ebd60f3790145721307c255e5a339923f /Software/Visual_Studio/Scripting/Tango.Scripting/Parsing | |
| parent | b4a71931ea52636c6b36376aa9d71697ccf73524 (diff) | |
| download | Tango-fc8a05358a92cc3c77c5f1e30d536807ef0614fd.tar.gz Tango-fc8a05358a92cc3c77c5f1e30d536807ef0614fd.zip | |
were added scripting projects
Diffstat (limited to 'Software/Visual_Studio/Scripting/Tango.Scripting/Parsing')
3 files changed, 436 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptParser.cs b/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptParser.cs new file mode 100644 index 000000000..15760c950 --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptParser.cs @@ -0,0 +1,382 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Tango.Scripting.Parsing +{ + public class ScriptParser + { + private const string fakeScript = "CurrentScript"; + private string fakeScriptName = "CurrentScript."; + + private String ReplaceFakeScript(String str) + { + if (str != null) + { + return str.Replace(fakeScriptName, "").Replace(fakeScript, ""); + } + + return str; + } + + private CompilationUnitSyntax GetRoot(String code) + { + SyntaxTree tree = CSharpSyntaxTree.ParseText(code); + var root = (CompilationUnitSyntax)tree.GetRoot(); + return root; + } + + private SemanticModel GetSemanticModel(String code) + { + SyntaxTree tree = CSharpSyntaxTree.ParseText(code); + CompilationUnitSyntax root = tree.GetCompilationUnitRoot(); + var compilation = CSharpCompilation.Create("CSharpScript").AddSyntaxTrees(tree); + SemanticModel model = compilation.GetSemanticModel(tree); + return model; + } + + public List<ScriptSymbol> GetContextSymbols(String code, int caretOffset) + { + var currentNode = GetCaretOffsetNode(code, caretOffset); + + if (currentNode == null) return new List<ScriptSymbol>(); + + if (currentNode.Ancestors().OfType<BaseTypeDeclarationSyntax>().Count() == 0) + { + var usings = GetUsingsFull(code); + + int removedLength = usings.Select(x => x.Length).Sum(); + + foreach (var use in usings) + { + code = code.Replace(use, ""); + } + + String scriptStart = $"public class {fakeScript}\n{{\n"; + code = $"{scriptStart}{code}\n}}"; + caretOffset = caretOffset - removedLength + scriptStart.Length; + } + + var model = GetSemanticModel(code); + var symbols = model.LookupSymbols(caretOffset).ToList().Where(x => x.Kind == SymbolKind.Property || x.Kind == SymbolKind.Field || x.Kind == SymbolKind.Parameter || x.Kind == SymbolKind.Local || x.Kind == SymbolKind.Method).ToList(); + + List<ScriptSymbol> vars = new List<ScriptSymbol>(); + + foreach (var symbol in symbols.DistinctBy(x => x.Name)) + { + if (symbol.ContainingSymbol.GetType().Name == "LambdaSymbol") + { + var invocationNode = currentNode.Ancestors().OfType<InvocationExpressionSyntax>().FirstOrDefault(); + + if (invocationNode != null) + { + var expressionNode = invocationNode.Expression as MemberAccessExpressionSyntax; + + if (expressionNode != null && expressionNode.Name != null) + { + var name = expressionNode.Name as GenericNameSyntax; + + if (name != null) + { + var type = name.TypeArgumentList.Arguments.FirstOrDefault()?.ToString(); + + vars.Add(new ScriptSymbol() + { + Name = symbol.Name, + Type = ReplaceFakeScript(type), + Class = ReplaceFakeScript(symbol.ContainingType?.Name), + Kind = symbol.Kind, + Accessibility = symbol.DeclaredAccessibility, + ContainingNamespace = ReplaceFakeScript(symbol.ContainingNamespace?.Name), + Summary = GetSymbolDocumentation(symbol), + }); + } + } + } + } + if (symbol.Kind == SymbolKind.Method) + { + var prop = symbol.GetType().GetProperty("ReturnType"); + + if (prop != null) + { + ScriptSymbol m = new ScriptSymbol() + { + Name = symbol.Name, + Type = ReplaceFakeScript(prop.GetValue(symbol).ToString()), + Class = ReplaceFakeScript(symbol.ContainingType?.Name), + Kind = symbol.Kind, + Accessibility = symbol.DeclaredAccessibility, + ContainingNamespace = ReplaceFakeScript(symbol.ContainingNamespace?.Name), + Summary = GetSymbolDocumentation(symbol), + }; + + m.Parameters = GetMethodSymbolParameters(symbol); + + vars.Add(m); + } + } + else + { + var prop = symbol.GetType().GetProperty("Type"); + + if (prop != null) + { + vars.Add(new ScriptSymbol() + { + Name = symbol.Name, + Type = ReplaceFakeScript(prop.GetValue(symbol).ToString()), + Class = ReplaceFakeScript(symbol.ContainingType?.Name), + Kind = symbol.Kind, + Accessibility = symbol.DeclaredAccessibility, + ContainingNamespace = ReplaceFakeScript(symbol.ContainingNamespace?.Name), + Summary = GetSymbolDocumentation(symbol), + }); + } + } + } + + return vars.Where(x => x.Type != "?").ToList(); + } + + public List<String> GetUsings(String code) + { + Regex r = new Regex("(using [^;^\n]+;)"); + var matches = r.Matches(code); + return matches.OfType<Match>().Select(x => x.Value.Replace("using ", "").Replace(";", "").Replace("\n", "").Replace("\t", "").Replace("\r", "")).ToList(); + } + + public List<String> GetUsingsFull(String code) + { + Regex r = new Regex("(using [^;^\n]+;)"); + var matches = r.Matches(code); + return matches.OfType<Match>().Select(x => x.Value).ToList(); + } + + public List<ScriptType> GetDeclaredTypes(String code) + { + List<ScriptType> types = new List<ScriptType>(); + + SyntaxTree tree = CSharpSyntaxTree.ParseText(code); + CompilationUnitSyntax root = tree.GetCompilationUnitRoot(); + var compilation = CSharpCompilation.Create("CSharpScript").AddSyntaxTrees(tree); + SemanticModel model = compilation.GetSemanticModel(tree); + + foreach (var d in root.DescendantNodes().Where(x => x is ClassDeclarationSyntax || x is EnumDeclarationSyntax || x is InterfaceDeclarationSyntax).OfType<BaseTypeDeclarationSyntax>()) + { + var type = model.GetDeclaredSymbol(d); + if (!String.IsNullOrWhiteSpace(type.Name)) + { + ScriptType scriptType = new ScriptType(); + scriptType.Name = type.Name; + scriptType.Kind = type.TypeKind; + scriptType.ContainingNamespace = type.ContainingNamespace?.Name; + scriptType.Summary = GetNodeDocumentation(d); + + + foreach (var symbol in d.DescendantNodes().OfType<PropertyDeclarationSyntax>()) + { + var symbolModel = model.GetDeclaredSymbol(symbol); + + scriptType.Symbols.Add(new ScriptSymbol() + { + Class = scriptType.Name, + Accessibility = symbolModel.DeclaredAccessibility, + Kind = SymbolKind.Property, + Name = symbolModel.Name, + Type = symbolModel.Type.ToString(), + ContainingNamespace = symbolModel.ContainingNamespace?.Name, + Summary = GetNodeDocumentation(symbol), + }); + } + + foreach (var symbol in d.DescendantNodes().OfType<FieldDeclarationSyntax>()) + { + var symbolModel = model.GetDeclaredSymbol(symbol.Declaration.Variables.FirstOrDefault()) as IFieldSymbol; + + if (symbolModel != null) + { + scriptType.Symbols.Add(new ScriptSymbol() + { + Class = scriptType.Name, + Accessibility = symbolModel.DeclaredAccessibility, + Kind = SymbolKind.Field, + Name = symbolModel.Name, + Type = symbolModel.Type.ToString(), + ContainingNamespace = symbolModel.ContainingNamespace?.Name, + Summary = GetNodeDocumentation(symbol), + }); + } + } + + foreach (var symbol in d.DescendantNodes().OfType<MethodDeclarationSyntax>()) + { + var symbolModel = model.GetDeclaredSymbol(symbol); + + if (symbolModel != null) + { + ScriptSymbol m = new ScriptSymbol() + { + Class = scriptType.Name, + Accessibility = symbolModel.DeclaredAccessibility, + Kind = SymbolKind.Method, + Name = symbolModel.Name, + Type = symbolModel.ReturnType.ToString(), + ContainingNamespace = symbolModel.ContainingNamespace?.Name, + Summary = GetNodeDocumentation(symbol), + }; + + foreach (var p in symbol.DescendantNodes().OfType<ParameterSyntax>()) + { + if (p.Type != null && p.Identifier != null) + { + m.Parameters.Add(new KeyValuePair<string, string>(p.Type.ToString(), p.Identifier.ToString())); + } + } + + scriptType.Symbols.Add(m); + } + } + + types.Add(scriptType); + } + } + + return types; + } + + public ObjectCreationExpressionSyntax GetCurrentConstructionExpression(String code) + { + SyntaxTree tree = CSharpSyntaxTree.ParseText(code); + CompilationUnitSyntax root = tree.GetCompilationUnitRoot(); + return root.DescendantNodes().OfType<ObjectCreationExpressionSyntax>().FirstOrDefault(); + } + + public T GetExpressionFirst<T>(String line) where T : CSharpSyntaxNode + { + SyntaxTree tree = CSharpSyntaxTree.ParseText(line); + CompilationUnitSyntax root = tree.GetCompilationUnitRoot(); + return root.DescendantNodes().OfType<T>().FirstOrDefault(); + } + + public List<T> GetExpressions<T>(String line) where T : CSharpSyntaxNode + { + SyntaxTree tree = CSharpSyntaxTree.ParseText(line); + CompilationUnitSyntax root = tree.GetCompilationUnitRoot(); + return root.DescendantNodes().OfType<T>().ToList(); + } + + public List<T> GetDirectExpressions<T>(SyntaxNode node) where T : CSharpSyntaxNode + { + return node.DescendantNodes().OfType<T>().ToList(); + } + + private SyntaxNode GetCaretOffsetNode(String code, int offset) + { + SyntaxTree tree = CSharpSyntaxTree.ParseText(code); + CompilationUnitSyntax root = tree.GetCompilationUnitRoot(); + return root.DescendantNodes().Where(x => offset >= x.FullSpan.Start && offset <= x.FullSpan.End).OrderBy(x => x.FullSpan.Length).FirstOrDefault(); + } + + private List<SyntaxNode> GetNodeAncestors(SyntaxNode node) + { + return node.Ancestors().ToList(); + } + + private String GetNodeDocumentation(SyntaxNode node) + { + try + { + var trivia = node.GetLeadingTrivia().FirstOrDefault(t => t.Kind() == SyntaxKind.SingleLineCommentTrivia); + + if (trivia != null && !String.IsNullOrWhiteSpace(trivia.ToString())) + { + return trivia.ToString().Replace("//", ""); + } + } + catch { } + + return "No documentation."; + } + + private String GetSymbolDocumentation(ISymbol symbol) + { + if (symbol != null) + { + var prop = symbol.GetType().GetProperty("SyntaxNode"); + + if (prop != null) + { + var node = prop.GetValue(symbol) as SyntaxNode; + + if (node != null) + { + return GetNodeDocumentation(node.Parent); + } + } + } + + return "No documentation."; + } + + private SyntaxNode GetSymbolSyntaxNode(ISymbol symbol) + { + if (symbol != null) + { + var prop = symbol.GetType().GetProperty("SyntaxNode"); + + if (prop != null) + { + var node = prop.GetValue(symbol) as SyntaxNode; + + return node; + } + } + + return null; + } + + private List<KeyValuePair<String, String>> GetMethodSymbolParameters(ISymbol symbol) + { + List<KeyValuePair<String, String>> parameters = new List<KeyValuePair<string, string>>(); + + try + { + var prop = symbol.GetType().GetProperty("Parameters"); + + if (prop != null) + { + var array = prop.GetValue(symbol) as IEnumerable; + + foreach (var item in array) + { + var type = item.GetType().GetProperty("Type").GetValue(item).ToString(); + var value = item.GetType().GetProperty("Name").GetValue(item).ToString(); + + parameters.Add(new KeyValuePair<string, string>(type, value)); + } + } + } + catch { } + + return parameters; + } + + public String IndentCSharpCode(String code) + { + var tree = CSharpSyntaxTree.ParseText(code); + var root = tree.GetRoot().NormalizeWhitespace(); + var ret = root.ToFullString(); + return ret; + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptSymbol.cs b/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptSymbol.cs new file mode 100644 index 000000000..d6fdaeebf --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptSymbol.cs @@ -0,0 +1,31 @@ +using Microsoft.CodeAnalysis; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Parsing +{ + public class ScriptSymbol + { + public String Name { get; set; } + public String Type { get; set; } + public SymbolKind Kind { get; set; } + public String Class { get; set; } + public Accessibility Accessibility { get; set; } + public String ContainingNamespace { get; set; } + public List<KeyValuePair<String,String>> Parameters { get; set; } + public String Summary { get; set; } + + public ScriptSymbol() + { + Parameters = new List<KeyValuePair<string, string>>(); + } + + public override string ToString() + { + return $"{Kind.ToString()} : {Type} : {Name}"; + } + } +} diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptType.cs b/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptType.cs new file mode 100644 index 000000000..3ca34a85e --- /dev/null +++ b/Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptType.cs @@ -0,0 +1,23 @@ +using Microsoft.CodeAnalysis; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting.Parsing +{ + public class ScriptType + { + public String Name { get; set; } + public TypeKind Kind { get; set; } + public List<ScriptSymbol> Symbols { get; set; } + public string ContainingNamespace { get; set; } + public String Summary { get; set; } + + public ScriptType() + { + Symbols = new List<ScriptSymbol>(); + } + } +} |
