pascalabcnet/VisualPascalABCNETLinux/IB/CodeCompletion/CodeCompletionParserController.cs
AlexanderZemlyak 2e27beef48
Create generic instances cache (#3259)
* First attempt to create generic instances cache

* Change TypeScope equality check and add instance cache clearing

* Move instance cache clearing call to CodeCompletion Compile funciton

Шаблонные типы в instance_cache не должны пересекаться для различных модулей. Для улучшения производительности вызов очистки кэша расположен перед вызовом компиляции всех модулей.

* Squashed commit of the following:

commit 771ea7b445
Author: Ivan Bondarev <ibond84@googlemail.com>
Date:   Sun Apr 6 14:32:17 2025 +0200

    #3230

commit 28a1a03e8d
Author: Ivan Bondarev <ibond84@googlemail.com>
Date:   Sun Apr 6 11:35:09 2025 +0200

    #3251

commit af7abc770b
Author: samuraiGH <87191377+samuraiGH@users.noreply.github.com>
Date:   Sun Apr 6 08:33:34 2025 +0300

    synchronization of namespaces and folders for TeacherControlPlugin (#3262)

commit aae723b982
Author: AlexanderZemlyak <92867056+AlexanderZemlyak@users.noreply.github.com>
Date:   Thu Apr 3 12:00:04 2025 +0300

    Create default syntax tree converter class (#3216)

    Для удобства разработчиков простых языков, которым не требуются дополнительные обходы синтаксического дерева.

commit f9cc90e50f
Author: Sun Serega <sunserega2@gmail.com>
Date:   Thu Apr 3 11:59:46 2025 +0300

    fix errors (#3260)

commit f85bfad60f
Author: AlexanderZemlyak <92867056+AlexanderZemlyak@users.noreply.github.com>
Date:   Thu Apr 3 11:58:19 2025 +0300

    Intellisense memory leaks fix (#3257)

    * Fix memory leaks found for PABCSystem.pas

    Memory leaks of Interface and Implementation Unit Scopes fixed

    * Change open_files and recomp_files variables type to be Dictionary (not HashTable)

    * open_files Check simplification

    * Move TypeTable.Clear call to CodeCompletion Compile method

* Fix incorrect dictionary iteration

* Add one more dictionary keys copying
2025-04-10 13:14:04 +03:00

280 lines
12 KiB
C#

// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
namespace VisualPascalABC
{
public delegate void ParseInformationUpdatedDelegate(object obj, string fileName);
public class CodeCompletionParserController : VisualPascalABCPlugins.ICodeCompletionService
{
public static Dictionary<string, bool> open_files = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
public VisualEnvironmentCompiler visualEnvironmentCompiler;
private System.Threading.Thread th = null;
private CodeCompletionProvider ccp;
public event ParseInformationUpdatedDelegate ParseInformationUpdated;
public void StopParseThread()
{
try
{
if (th != null)
{
IsDone = true;
th.Abort(); // надо бы заменить на что то современное
th.Join();
}
}
catch
{
}
}
public CodeCompletionParserController()
{
this.th = new System.Threading.Thread(new System.Threading.ThreadStart(ParseInThread));
ccp = new CodeCompletionProvider();
}
public PascalABCCompiler.Parsers.ICodeCompletionDomConverter GetConverter(string fileName)
{
return CodeCompletion.CodeCompletionController.comp_modules[fileName] as PascalABCCompiler.Parsers.ICodeCompletionDomConverter;
}
public static string CurrentTwoLetterISO
{
get
{
return CodeCompletion.CodeCompletionController.currentLanguageISO;
}
set
{
CodeCompletion.CodeCompletionController.currentLanguageISO = value;
}
}
public void Init()
{
//LanguageProvider.Instance.SourceFilesProvider = visualEnvironmentCompiler.SourceFilesProvider;
CodeCompletion.CodeCompletionController.currentLanguageISO = PascalABCCompiler.StringResourcesLanguage.CurrentTwoLetterISO;
}
public void RenameFile(string OldFileName, string NewFileName)
{
if (string.Compare(OldFileName, NewFileName, true) != 0)
{
CodeCompletion.CodeCompletionController.comp_modules[NewFileName] = CodeCompletion.CodeCompletionController.comp_modules[OldFileName];
if (CodeCompletion.CodeCompletionController.comp_modules.ContainsKey(OldFileName))
CodeCompletion.CodeCompletionController.comp_modules.Remove(OldFileName);
open_files[NewFileName] = open_files[OldFileName];
if (open_files.ContainsKey(OldFileName))
open_files.Remove(OldFileName);
}
}
public void RegisterFileForParsing(string FileName)
{
open_files[FileName] = true;
CodeCompletion.CodeCompletionController.SetParser(System.IO.Path.GetExtension(FileName));
//ParseAllFiles();
}
public void CloseFile(string FileName)
{
if (CodeCompletion.CodeCompletionController.comp_modules[FileName] != null)
CodeCompletion.CodeCompletionController.comp_modules.Remove(FileName);
open_files.Remove(FileName);
}
public void SetAsChanged(string FileName)
{
if (FileName != null)
open_files[FileName] = true;
}
public void SetAllInProjectChanged()
{
try
{
foreach (string s in open_files.Keys.ToArray())
{
if (ProjectFactory.Instance.CurrentProject.ContainsSourceFile(s))
open_files[s] = true;
}
}
catch (Exception e)
{
}
}
public void RunParseThread()
{
th = new System.Threading.Thread(InternalParsing);
th.Priority = System.Threading.ThreadPriority.BelowNormal;
th.IsBackground = true;
th.Start();
}
public void StopParsing()
{
try
{
VisualPABCSingleton.MainForm.StopTimer();
}
catch
{
}
}
private volatile bool IsDone = false;
private void InternalParsing()
{
while (!IsDone)
{
ParseInThread();
if (IsDone)
break;
System.Threading.Thread.Sleep(2000);
}
}
private long mem_delta = 0;
internal void ParseInThread()
{
try
{
Dictionary<string, string> recomp_files = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
bool is_comp = false;
foreach (string FileName in open_files.Keys.ToArray()) // копирование ключей обязательно, иначе будет InvalidOperationException EVA
{
if (open_files[FileName])
{
is_comp = true;
CodeCompletion.CodeCompletionController controller = new CodeCompletion.CodeCompletionController();
string text = visualEnvironmentCompiler.SourceFilesProvider(FileName, PascalABCCompiler.SourceFileOperation.GetText) as string;
if (string.IsNullOrEmpty(text))
text = "begin end.";
CodeCompletion.DomConverter tmp = CodeCompletion.CodeCompletionController.comp_modules[FileName] as CodeCompletion.DomConverter;
long cur_mem = Environment.WorkingSet;
CodeCompletion.DomConverter dc = controller.Compile(FileName, text);
mem_delta += Environment.WorkingSet - cur_mem;
open_files[FileName] = false;
if (dc.is_compiled)
{
//CodeCompletion.CodeCompletionController.comp_modules.Remove(file_name);
if (tmp != null && tmp.visitor.entry_scope != null)
{
tmp.visitor.entry_scope.Clear();
if (tmp.visitor.cur_scope != null)
tmp.visitor.cur_scope.Clear();
}
CodeCompletion.CodeCompletionController.comp_modules[FileName] = dc;
recomp_files[FileName] = FileName;
open_files[FileName] = false;
if (ParseInformationUpdated != null)
ParseInformationUpdated(dc.visitor.entry_scope, FileName);
}
else if (CodeCompletion.CodeCompletionController.comp_modules[FileName] == null)
CodeCompletion.CodeCompletionController.comp_modules[FileName] = dc;
}
}
foreach (string FileName in open_files.Keys.ToArray()) // копирование ключей обязательно, иначе будет InvalidOperationException EVA
{
CodeCompletion.DomConverter dc = CodeCompletion.CodeCompletionController.comp_modules[FileName] as CodeCompletion.DomConverter;
CodeCompletion.SymScope ss = null;
if (dc != null)
{
if (dc.visitor.entry_scope != null) ss = dc.visitor.entry_scope;
else if (dc.visitor.impl_scope != null) ss = dc.visitor.impl_scope;
int j = 0;
while (j < 2)
{
if (j == 0)
{
ss = dc.visitor.entry_scope;
j++;
}
else
{
ss = dc.visitor.impl_scope;
j++;
}
if (ss != null)
{
for (int i = 0; i < ss.used_units.Count; i++)
{
string s = ss.used_units[i].file_name;
if (s != null && open_files.ContainsKey(s) && recomp_files.ContainsKey(s))
{
is_comp = true;
CodeCompletion.CodeCompletionController controller = new CodeCompletion.CodeCompletionController();
string text = visualEnvironmentCompiler.SourceFilesProvider(FileName, PascalABCCompiler.SourceFileOperation.GetText) as string;
CodeCompletion.DomConverter tmp = CodeCompletion.CodeCompletionController.comp_modules[FileName] as CodeCompletion.DomConverter;
long cur_mem = Environment.WorkingSet;
dc = controller.Compile(FileName, text);
mem_delta += Environment.WorkingSet - cur_mem;
open_files[FileName] = false;
CodeCompletion.CodeCompletionController.comp_modules[FileName] = dc;
if (dc.is_compiled)
{
/*if (tmp != null && tmp.stv.entry_scope != null)
{
tmp.stv.entry_scope.Clear();
if (tmp.stv.cur_scope != null) tmp.stv.cur_scope.Clear();
}*/
CodeCompletion.CodeCompletionController.comp_modules[FileName] = dc;
recomp_files[FileName] = FileName;
ss.used_units[i] = dc.visitor.entry_scope;
if (ParseInformationUpdated != null)
ParseInformationUpdated(dc.visitor.entry_scope, FileName);
}
else if (CodeCompletion.CodeCompletionController.comp_modules[FileName] == null)
CodeCompletion.CodeCompletionController.comp_modules[FileName] = dc;
}
}
}
}
}
}
if (is_comp && mem_delta > 20000000 /*&& mem_delta > 10000000*/)
//postavil delta dlja pamjati, posle kototoj delaetsja sborka musora
{
mem_delta = 0;
GC.Collect();
}
}
catch (Exception) { }
}
public bool IsParsing()
{
return th != null && th.ThreadState == System.Threading.ThreadState.Running;
}
public void ParseAllFiles()
{
if (visualEnvironmentCompiler.UserOptions.AllowCodeCompletion)// && visualEnvironmentCompiler.compilerLoaded)
{
if (th.ThreadState != System.Threading.ThreadState.Running)
{
th = new System.Threading.Thread(new System.Threading.ThreadStart(this.ParseInThread));
th.Priority = System.Threading.ThreadPriority.BelowNormal;
//th.IsBackground = true;
th.Start();
}
//if (th == null)
// RunParseThread();
}
}
}
}