From fc8a05358a92cc3c77c5f1e30d536807ef0614fd Mon Sep 17 00:00:00 2001 From: Victoria Plitt Date: Mon, 8 Apr 2019 13:49:55 +0300 Subject: were added scripting projects --- .../Tango.Scripting/Parsing/ScriptParser.cs | 382 +++++++++++++++++++++ 1 file changed, 382 insertions(+) create mode 100644 Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptParser.cs (limited to 'Software/Visual_Studio/Scripting/Tango.Scripting/Parsing/ScriptParser.cs') 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 GetContextSymbols(String code, int caretOffset) + { + var currentNode = GetCaretOffsetNode(code, caretOffset); + + if (currentNode == null) return new List(); + + if (currentNode.Ancestors().OfType().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 vars = new List(); + + foreach (var symbol in symbols.DistinctBy(x => x.Name)) + { + if (symbol.ContainingSymbol.GetType().Name == "LambdaSymbol") + { + var invocationNode = currentNode.Ancestors().OfType().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 GetUsings(String code) + { + Regex r = new Regex("(using [^;^\n]+;)"); + var matches = r.Matches(code); + return matches.OfType().Select(x => x.Value.Replace("using ", "").Replace(";", "").Replace("\n", "").Replace("\t", "").Replace("\r", "")).ToList(); + } + + public List GetUsingsFull(String code) + { + Regex r = new Regex("(using [^;^\n]+;)"); + var matches = r.Matches(code); + return matches.OfType().Select(x => x.Value).ToList(); + } + + public List GetDeclaredTypes(String code) + { + List types = new List(); + + 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()) + { + 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()) + { + 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()) + { + 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()) + { + 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()) + { + if (p.Type != null && p.Identifier != null) + { + m.Parameters.Add(new KeyValuePair(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().FirstOrDefault(); + } + + public T GetExpressionFirst(String line) where T : CSharpSyntaxNode + { + SyntaxTree tree = CSharpSyntaxTree.ParseText(line); + CompilationUnitSyntax root = tree.GetCompilationUnitRoot(); + return root.DescendantNodes().OfType().FirstOrDefault(); + } + + public List GetExpressions(String line) where T : CSharpSyntaxNode + { + SyntaxTree tree = CSharpSyntaxTree.ParseText(line); + CompilationUnitSyntax root = tree.GetCompilationUnitRoot(); + return root.DescendantNodes().OfType().ToList(); + } + + public List GetDirectExpressions(SyntaxNode node) where T : CSharpSyntaxNode + { + return node.DescendantNodes().OfType().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 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> GetMethodSymbolParameters(ISymbol symbol) + { + List> parameters = new List>(); + + 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(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; + } + } +} -- cgit v1.3.1