From c96ecaf239db6d1270958841e2efd9fba3360c6e Mon Sep 17 00:00:00 2001 From: Roy Ben-Shabat Date: Mon, 11 Mar 2019 13:59:39 +0200 Subject: Working on script engine. --- .../Highlighting/Resources/CSharp-Mode.xshd | 2 + .../Tango.Scripting.Editors/Images/field.png | Bin 0 -> 395 bytes .../Tango.Scripting.Editors/Images/property.png | Bin 316 -> 363 bytes .../Intellisense/FieldCompletionItem.cs | 20 ++ .../Intellisense/FieldCompletionItemPopup.cs | 25 +++ .../Tango.Scripting.Editors/ScriptEditor.cs | 217 +++++++++++++-------- .../Tango.Scripting.Editors.csproj | 7 +- .../Tango.Scripting.Editors/Themes/Generic.xaml | 23 +++ .../Tango.Scripting/Parsing/ScriptParser.cs | 102 +++++----- .../Tango.Scripting/Parsing/ScriptVariable.cs | 9 +- .../Tango.Scripting/Tango.Scripting.csproj | 3 + 11 files changed, 277 insertions(+), 131 deletions(-) create mode 100644 Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Images/field.png create mode 100644 Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Intellisense/FieldCompletionItem.cs create mode 100644 Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Intellisense/FieldCompletionItemPopup.cs (limited to 'Software/Visual_Studio/TEMP') diff --git a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSharp-Mode.xshd b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSharp-Mode.xshd index 1ba2cbc6f..40f362e08 100644 --- a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSharp-Mode.xshd +++ b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Highlighting/Resources/CSharp-Mode.xshd @@ -184,6 +184,8 @@ dynamic await void + interface + this diff --git a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Images/field.png b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Images/field.png new file mode 100644 index 000000000..37de414e9 Binary files /dev/null and b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Images/field.png differ diff --git a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Images/property.png b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Images/property.png index 001a8c66a..4abd1a4a4 100644 Binary files a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Images/property.png and b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Images/property.png differ diff --git a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Intellisense/FieldCompletionItem.cs b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Intellisense/FieldCompletionItem.cs new file mode 100644 index 000000000..3b1996174 --- /dev/null +++ b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Intellisense/FieldCompletionItem.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media.Imaging; + +namespace Tango.Scripting.Editors.Intellisense +{ + public class FieldCompletionItem : CompletionItem + { + public override string Text => Name; + public override CompletionItemPopupControl PopupControl => new FieldCompletionItemPopup(); + public override BitmapSource Image => GetImage("field.png"); + + public String Name { get; set; } + public String Class { get; set; } + public String Type { get; set; } + } +} diff --git a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Intellisense/FieldCompletionItemPopup.cs b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Intellisense/FieldCompletionItemPopup.cs new file mode 100644 index 000000000..e1ea3ce55 --- /dev/null +++ b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Intellisense/FieldCompletionItemPopup.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.Scripting.Editors.Intellisense +{ + public class FieldCompletionItemPopup : CompletionItemPopupControl + { + static FieldCompletionItemPopup() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(FieldCompletionItemPopup), new FrameworkPropertyMetadata(typeof(FieldCompletionItemPopup))); + } + } +} diff --git a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/ScriptEditor.cs b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/ScriptEditor.cs index 49d745d6c..64fb0f194 100644 --- a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/ScriptEditor.cs +++ b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/ScriptEditor.cs @@ -400,7 +400,7 @@ namespace Tango.Scripting.Editors if (variableName != null && tree.Count > 1) { tree.RemoveAt(0); - var variables = _parser.GetScriptVariables(Document.Text); + var variables = _parser.GetContextSymbols(Document.Text, CaretOffset); var variable = variables.FirstOrDefault(x => x.Name == variableName); if (variable != null) @@ -449,8 +449,6 @@ namespace Tango.Scripting.Editors private void InvalidateHighlighting() { - _parser.GetDeclaredTypes(Text); - _knownTypes.Clear(); var assemblies = ReferenceAssemblies.ToList(); @@ -689,7 +687,7 @@ namespace Tango.Scripting.Editors if (e.Text == " " && GetPreviousWord() == "new") { - var s = _parser.GetExpression(GetCurrentLineText()); + var s = _parser.GetExpressionFirst(GetCurrentLineText()); if (s != null) { @@ -835,100 +833,153 @@ namespace Tango.Scripting.Editors if (!String.IsNullOrWhiteSpace(word)) { - if (char.IsUpper(word.First())) - { - IList data = new List(); + IList data = new List(); - foreach (var type in _declaredTypes.Where(x => x.Name.StartsWith(word))) + foreach (var type in _declaredTypes.Where(x => x.Name.StartsWith(word))) + { + if (type.TypeKind == TypeKind.Struct) { - if (type.TypeKind == TypeKind.Struct) - { - data.Add(new StructCompletionItem() - { - Name = type.Name, - Description = "Declared inside the current script...", - Namespace = type.ContainingNamespace?.Name, - }); - } - else if (type.TypeKind == TypeKind.Enum) + data.Add(new StructCompletionItem() { - data.Add(new EnumCompletionItem() - { - Name = type.Name, - Description = "Declared inside the current script...", - Namespace = type.ContainingNamespace?.Name, - }); - } - else if (type.TypeKind == TypeKind.Interface) + Name = type.Name, + Description = "Declared inside the current script...", + Namespace = type.ContainingNamespace?.Name, + Priority = 1, + }); + } + else if (type.TypeKind == TypeKind.Enum) + { + data.Add(new EnumCompletionItem() { - data.Add(new InterfaceCompletionItem() - { - Name = type.Name, - Description = "Declared inside the current script...", - Namespace = type.ContainingNamespace?.Name, - }); - } - else if (type.TypeKind == TypeKind.Class) + Name = type.Name, + Description = "Declared inside the current script...", + Namespace = type.ContainingNamespace?.Name, + Priority = 1, + }); + } + else if (type.TypeKind == TypeKind.Interface) + { + data.Add(new InterfaceCompletionItem() { - data.Add(new ClassCompletionItem() - { - Name = type.Name, - Description = "Declared inside the current script...", - Namespace = type.ContainingNamespace?.Name, - }); - } - else + Name = type.Name, + Description = "Declared inside the current script...", + Namespace = type.ContainingNamespace?.Name, + Priority = 1, + }); + } + else if (type.TypeKind == TypeKind.Class) + { + data.Add(new ClassCompletionItem() { - throw new NotImplementedException("Implement generic item here!"); - } + Name = type.Name, + Description = "Declared inside the current script...", + Namespace = type.ContainingNamespace?.Name, + Priority = 1, + }); } + else + { + throw new NotImplementedException("Implement generic item here!"); + } + } - foreach (var type in _knownTypes.Where(x => x.Name.StartsWith(word))) + foreach (var type in _knownTypes.Where(x => x.Name.StartsWith(word))) + { + if (type.Type.IsEnum) { - if (type.Type.IsEnum) + data.Add(new EnumCompletionItem() { - data.Add(new EnumCompletionItem() - { - Namespace = type.Type.Namespace, - Description = type.Summary, - Name = type.FriendlyName, - }); - } - else if (type.Type.IsInterface) - { - data.Add(new InterfaceCompletionItem() - { - Name = type.FriendlyName, - Description = type.Summary, - Namespace = type.Type.Namespace, - }); - } - else if (type.Type.IsValueType) + Namespace = type.Type.Namespace, + Description = type.Summary, + Name = type.FriendlyName, + Priority = 0, + }); + } + else if (type.Type.IsInterface) + { + data.Add(new InterfaceCompletionItem() { - data.Add(new StructCompletionItem() - { - Name = type.FriendlyName, - Description = type.Summary, - Namespace = type.Type.Namespace, - }); - } - else if (type.Type.IsClass) + Name = type.FriendlyName, + Description = type.Summary, + Namespace = type.Type.Namespace, + Priority = 0, + }); + } + else if (type.Type.IsValueType) + { + data.Add(new StructCompletionItem() { - data.Add(new ClassCompletionItem() - { - Name = type.FriendlyName, - Description = type.Summary, - Namespace = type.Type.Namespace, - }); - } - else + Name = type.FriendlyName, + Description = type.Summary, + Namespace = type.Type.Namespace, + Priority = 0, + }); + } + else if (type.Type.IsClass) + { + data.Add(new ClassCompletionItem() { - throw new NotImplementedException("Implement generic item here."); - } + Name = type.FriendlyName, + Description = type.Summary, + Namespace = type.Type.Namespace, + Priority = 0, + }); } + else + { + throw new NotImplementedException("Implement generic item here."); + } + } - ShowCompletionWindow(data, word); + foreach (var symbol in _parser.GetContextSymbols(Document.Text, CaretOffset)) + { + if (symbol.Kind == SymbolKind.Property) + { + data.Add(new PropertyCompletionItem() + { + Class = symbol.Class, + Description = "Property defined in this script.", + Name = symbol.Name, + Type = symbol.Type, + Priority = 2, + }); + } + else if (symbol.Kind == SymbolKind.Field) + { + data.Add(new FieldCompletionItem() + { + Class = symbol.Class, + Description = "Field defined in this script.", + Name = symbol.Name, + Type = symbol.Type, + Priority = 2, + }); + } + else if (symbol.Kind == SymbolKind.Parameter) + { + data.Add(new FieldCompletionItem() + { + Class = symbol.Class, + Description = "Method parameter defined in this script.", + Name = symbol.Name, + Type = symbol.Type, + Priority = 2, + }); + } + else if (symbol.Kind == SymbolKind.Method) + { + data.Add(new MethodCompletionItem() + { + Class = symbol.Class, + Description = "Method defined in this script.", + Name = symbol.Name, + ReturnType = symbol.Type, + Priority = 2, + }); + } } + + ShowCompletionWindow(data, word); } } } @@ -1027,7 +1078,7 @@ namespace Tango.Scripting.Editors if (variableName != null) { tree.RemoveAt(0); - var variables = _parser.GetScriptVariables(Document.Text); + var variables = _parser.GetContextSymbols(Document.Text, CaretOffset); var variable = variables.FirstOrDefault(x => x.Name == variableName); if (variable != null) diff --git a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors.csproj b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors.csproj index 5422ba805..e5960a664 100644 --- a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors.csproj +++ b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Tango.Scripting.Editors.csproj @@ -197,6 +197,8 @@ + + @@ -615,9 +617,12 @@ + + + - + \ No newline at end of file diff --git a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Themes/Generic.xaml b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Themes/Generic.xaml index 7a6588239..1ab9dd2db 100644 --- a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Themes/Generic.xaml +++ b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting.Editors/Themes/Generic.xaml @@ -531,4 +531,27 @@ + + diff --git a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Parsing/ScriptParser.cs b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Parsing/ScriptParser.cs index 5564296e8..43a5a6b54 100644 --- a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Parsing/ScriptParser.cs +++ b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Parsing/ScriptParser.cs @@ -26,61 +26,51 @@ namespace Tango.Scripting.Parsing CompilationUnitSyntax root = tree.GetCompilationUnitRoot(); var compilation = CSharpCompilation.Create("CSharpScript").AddSyntaxTrees(tree); SemanticModel model = compilation.GetSemanticModel(tree); - return model; } - public List GetScriptVariables(String code) + public List GetContextSymbols(String code, int caretOffset) { - List vars = new List(); + 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(); - SyntaxTree tree = CSharpSyntaxTree.ParseText(code); - var root = (CompilationUnitSyntax)tree.GetRoot(); + List vars = new List(); - List variables = new List(); - FillVariables(variables, root.Members[0]); - variables = variables.Distinct().ToList(); - - foreach (var item in variables) + foreach (var symbol in symbols.DistinctBy(x => x.Name)) { - ScriptVariable v = new ScriptVariable(); - v.Type = item.Type.ToString(); - - var variable = item.Variables.FirstOrDefault(); - - if (variable != null) + if (symbol.Kind == SymbolKind.Method) { - //if (variable.Initializer.Value.GetType() == typeof(ObjectCreationExpressionSyntax)) - //{ - // v.Type = (variable.Initializer.Value as ObjectCreationExpressionSyntax).Type.ToString(); - //} - //else if (variable.Initializer.Value.GetType() == typeof(InvocationExpressionSyntax)) - //{ - // v.Type = (((variable.Initializer.Value as InvocationExpressionSyntax).Expression as MemberAccessExpressionSyntax).Name as GenericNameSyntax).TypeArgumentList.Arguments[0].ToString(); - //} - - v.Name = variable.Identifier.ToString(); - } - - vars.Add(v); - } - - return vars; - } - - private void FillVariables(List variables, SyntaxNode node) - { - foreach (var item in node.DescendantNodes(x => true)) - { - if (item.GetType() == typeof(VariableDeclarationSyntax)) - { - variables.Add(item as VariableDeclarationSyntax); + var prop = symbol.GetType().GetProperty("ReturnType"); + + if (prop != null) + { + vars.Add(new ScriptSymbol() + { + Name = symbol.Name, + Type = prop.GetValue(symbol).ToString(), + Class = symbol.ContainingType?.Name, + Kind = symbol.Kind, + }); + } } else { - FillVariables(variables, item); + var prop = symbol.GetType().GetProperty("Type"); + + if (prop != null) + { + vars.Add(new ScriptSymbol() + { + Name = symbol.Name, + Type = prop.GetValue(symbol).ToString(), + Class = symbol.ContainingType?.Name, + Kind = symbol.Kind, + }); + } } } + + return vars; } public List GetUsings(String code) @@ -99,7 +89,7 @@ namespace Tango.Scripting.Parsing var compilation = CSharpCompilation.Create("CSharpScript").AddSyntaxTrees(tree); SemanticModel model = compilation.GetSemanticModel(tree); - foreach (var d in root.DescendantNodes().OfType()) + 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)) @@ -118,11 +108,35 @@ namespace Tango.Scripting.Parsing return root.DescendantNodes().OfType().FirstOrDefault(); } - public T GetExpression(String line) where T : CSharpSyntaxNode + 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(); + } } } diff --git a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Parsing/ScriptVariable.cs b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Parsing/ScriptVariable.cs index c843e07c6..50b3fdd7e 100644 --- a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Parsing/ScriptVariable.cs +++ b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Parsing/ScriptVariable.cs @@ -1,4 +1,5 @@ -using System; +using Microsoft.CodeAnalysis; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,14 +7,16 @@ using System.Threading.Tasks; namespace Tango.Scripting.Parsing { - public class ScriptVariable + public class ScriptSymbol { public String Name { get; set; } public String Type { get; set; } + public SymbolKind Kind { get; set; } + public String Class { get; set; } public override string ToString() { - return String.Format("{0} : {1}", Type, Name); + return $"{Kind.ToString()} : {Type} : {Name}"; } } } diff --git a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Tango.Scripting.csproj b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Tango.Scripting.csproj index 71d1da005..f5d0175e7 100644 --- a/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Tango.Scripting.csproj +++ b/Software/Visual_Studio/TEMP/Tango.Scripting/Tango.Scripting/Tango.Scripting.csproj @@ -114,6 +114,9 @@ ..\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll + + ..\..\..\Build\Core\Debug\Tango.Core.dll + -- cgit v1.3.1