From 4e871c1f3a3fb65e48dfa99f26f673b7f376abed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=97=D0=B5=D0=BC=D0=BB=D1=8F=D0=BA?= <92867056+AlexanderZemlyak@users.noreply.github.com> Date: Sat, 29 Nov 2025 14:27:00 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D1=85=20=D1=81=20=D0=B8=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=BC,=20=D1=81=D0=BE=D0=B2=D0=BF=D0=B0=D0=B4=D0=B0?= =?UTF-8?q?=D1=8E=D1=89=D0=B8=D0=BC=20=D1=81=20=D0=B8=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B0=D0=BC=D0=B8=20=D1=81=D1=83=D1=89=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B5=D0=B9=20=D0=B8=D0=B7=20=D0=B4=D1=80=D1=83=D0=B3=D0=B8?= =?UTF-8?q?=D1=85=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D0=B5=D0=B9,=20=D0=B2?= =?UTF-8?q?=20SPython=20(#3360)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix variables with special names declaration in SPython * Add new syntax tree converters applying flag checking in Intellisense * Fix IsVariableOrConstant function in Intellisense * Optimize CollectNamesFromUsedUnits function in Compiler --- CodeCompletion/DomSyntaxTreeVisitor.cs | 26 ++++++--- CodeExamples/SPython/delete_by_mouse.pys | 2 +- Compiler/Compiler.cs | 51 +++++++++++++----- .../SPythonLanguageInformation.cs | 2 + .../NameCorrectVisitor.cs | 14 +++-- .../SymbolTableFillingVisitor.cs | 53 ++++++++++--------- .../ParserTools/BaseLanguageInformation.cs | 2 + .../ParserTools/ILanguageInformation.cs | 5 ++ .../PascalABCLanguageInformation.cs | 2 + ...pilationArtifactsUsedBySyntaxConverters.cs | 4 +- 10 files changed, 110 insertions(+), 51 deletions(-) diff --git a/CodeCompletion/DomSyntaxTreeVisitor.cs b/CodeCompletion/DomSyntaxTreeVisitor.cs index 9c17cc42a..28be778f0 100644 --- a/CodeCompletion/DomSyntaxTreeVisitor.cs +++ b/CodeCompletion/DomSyntaxTreeVisitor.cs @@ -2718,7 +2718,7 @@ namespace CodeCompletion } } - if (currentUnitLanguage.ApplySyntaxTreeConvertersForIntellisense) + if (currentUnitLanguage.ApplySyntaxTreeConvertersForIntellisense && currentUnitLanguage.LanguageInformation.SyntaxTreeIsConvertedAfterUsedModulesCompilation) { var namesFromUsedUnits = CollectNamesFromUsedUnits(cur_scope); @@ -2791,36 +2791,48 @@ namespace CodeCompletion } - private Dictionary> CollectNamesFromUsedUnits(SymScope currentUnitScope) + private Dictionary> CollectNamesFromUsedUnits(SymScope currentUnitScope) { - var namesFromUsedUnits = new Dictionary>(); + var namesFromUsedUnits = new Dictionary>(); + + bool IsVariableOrConstant(SymbolKind symKind) + { + return symKind == SymbolKind.Variable + || symKind == SymbolKind.Constant + || symKind == SymbolKind.Event; + } foreach (var unitScope in currentUnitScope.used_units) { if (unitScope is InterfaceUnitScope interfaceScope) { - namesFromUsedUnits.Add(unitScope.Name, new HashSet()); + namesFromUsedUnits.Add(unitScope.Name, new Dictionary()); foreach (var symbol in unitScope.symbol_table) { var scopesOrScope = ((DictionaryEntry)symbol).Value; string name; + bool isVariable; if (scopesOrScope is List scopes) { name = scopes[0].Name; + isVariable = IsVariableOrConstant(scopes[0].SymbolInfo.Kind); } else { - name = ((SymScope)scopesOrScope).Name; + var scope = (SymScope)scopesOrScope; + + name = scope.Name; + isVariable = IsVariableOrConstant(scope.SymbolInfo.Kind); } if (name == unitScope.Name) continue; - namesFromUsedUnits[unitScope.Name].Add(name); + namesFromUsedUnits[unitScope.Name][name] = isVariable; } } } @@ -3287,7 +3299,7 @@ namespace CodeCompletion } } - if (currentUnitLanguage.ApplySyntaxTreeConvertersForIntellisense) + if (currentUnitLanguage.ApplySyntaxTreeConvertersForIntellisense && currentUnitLanguage.LanguageInformation.SyntaxTreeIsConvertedAfterUsedModulesCompilation) { var namesFromUsedUnits = CollectNamesFromUsedUnits(cur_scope); diff --git a/CodeExamples/SPython/delete_by_mouse.pys b/CodeExamples/SPython/delete_by_mouse.pys index 1bb6b6a05..1a0c29675 100644 --- a/CodeExamples/SPython/delete_by_mouse.pys +++ b/CodeExamples/SPython/delete_by_mouse.pys @@ -12,7 +12,7 @@ def DrawStatusText(): StatusRect.Text = ('Удалено квадратов: ' + str(CurrentDigit-1) + '\tОшибок: ' + str(Mistakes)) else: - StatusRect.Text = ('Игра окончена. Время: ' + str(Milliseconds // 1000) + StatusRect.Text = ('Игра окончена. Время: ' + str(Milliseconds() // 1000) + ' с.\tОшибок: ' + str(Mistakes)) diff --git a/Compiler/Compiler.cs b/Compiler/Compiler.cs index 8951dea16..c8d520847 100644 --- a/Compiler/Compiler.cs +++ b/Compiler/Compiler.cs @@ -141,12 +141,12 @@ #define DEBUG +using Languages.Facade; using PascalABCCompiler.Errors; using PascalABCCompiler.PCU; using PascalABCCompiler.SemanticTreeConverters; using PascalABCCompiler.SyntaxTreeConverters; using PascalABCCompiler.TreeRealization; - using System; using System.CodeDom.Compiler; using System.Collections; @@ -155,8 +155,6 @@ using System.IO; using System.Linq; using System.Reflection; -using Languages.Facade; - namespace PascalABCCompiler { public enum UnitState { BeginCompilation, InterfaceCompiled, Compiled } @@ -240,8 +238,10 @@ namespace PascalABCCompiler /// /// Глобальные имена сущностей из зависимостей интерфейсной части + /// Внешний словарь по имени модуля выдает словарь сущностей. + /// Внутренний словарь по имени сущности выдает флаг о том, является ли она переменной. /// - public Dictionary> NamesFromUsedUnits { get; } = new Dictionary>(); + public Dictionary> NamesFromUsedUnits { get; } = new Dictionary>(); public UnitState State = UnitState.BeginCompilation; } @@ -3019,11 +3019,14 @@ namespace PascalABCCompiler //Console.WriteLine("Compiling Interface "+ unitFileName);//DEBUG - // заполняем currentUnit.NamesFromUsedUnits - CollectNamesFromUsedUnits(currentUnit); - - // конвертация синтаксического дерева с использованием данных из откомпилированных зависимостей - ConvertSyntaxTreeAfterUsedModulesCompilation(currentUnit); + if (currentUnit.Language.LanguageInformation.SyntaxTreeIsConvertedAfterUsedModulesCompilation) + { + // заполняем currentUnit.NamesFromUsedUnits + CollectNamesFromUsedUnits(currentUnit); + + // конвертация синтаксического дерева с использованием данных из откомпилированных зависимостей + ConvertSyntaxTreeAfterUsedModulesCompilation(currentUnit); + } // компилируем интерфейс текущего модуля EVA CompileCurrentUnitInterface(unitFileName, currentUnit, docs); @@ -3115,10 +3118,34 @@ namespace PascalABCCompiler string unitName = Path.GetFileNameWithoutExtension(unit.UnitFileName); - currentUnit.NamesFromUsedUnits.Add(unitName, new HashSet()); - foreach (var names in (unit.SemanticTree as common_unit_node).scope.Symbols.DictCaseSensitive.Skip(1)) + currentUnit.NamesFromUsedUnits.Add(unitName, new Dictionary()); + + var unitScope = (unit.SemanticTree as common_unit_node).scope; + + foreach (var names in unitScope.Symbols.DictCaseSensitive.Skip(1)) { - currentUnit.NamesFromUsedUnits[unitName].Add(names.Key); + definition_node symInfo = names.Value.InfoList[0].sym_info; + + // Если достаем из pcu, то надо восстановить полную информацию + if (symInfo is wrapped_definition_node wdn) + { + // У некоторых дубликатов sym_info offset не задан, ищем тот, где задан + symInfo = names.Value.InfoList.Find(si => ((wrapped_definition_node)si.sym_info).offset > 0)?.sym_info; + + if (symInfo == null) + continue; + + wdn = (wrapped_definition_node)symInfo; + + // Если это не синоним типа, то восстанавливаем семантическую информацию + if (!wdn.is_synonim) + symInfo = wdn.PCUReader.CreateInterfaceMember(wdn.offset, names.Key); + } + + currentUnit.NamesFromUsedUnits[unitName].Add(names.Key, + symInfo.general_node_type == general_node_type.variable_node + || symInfo.general_node_type == general_node_type.constant_definition + || symInfo.general_node_type == general_node_type.event_node); } } } diff --git a/LanguagePlugins/SPython/SPythonLanguageInfo/SPythonLanguageInformation.cs b/LanguagePlugins/SPython/SPythonLanguageInfo/SPythonLanguageInformation.cs index 421319fae..dc453f252 100644 --- a/LanguagePlugins/SPython/SPythonLanguageInfo/SPythonLanguageInformation.cs +++ b/LanguagePlugins/SPython/SPythonLanguageInfo/SPythonLanguageInformation.cs @@ -22,6 +22,8 @@ namespace Languages.SPython.Frontend.Data public override string[] SystemUnitNames => new string[] { "SPythonSystem", "SPythonHidden", "SPythonSystemPys" }; + public override bool SyntaxTreeIsConvertedAfterUsedModulesCompilation => true; + public override bool ApplySyntaxTreeConvertersForIntellisense => true; public override BaseKeywords KeywordsStorage { get; } = new SPythonParser.SPythonKeywords(); diff --git a/LanguagePlugins/SPython/SyntaxTreeConverters/SPythonStandardTreeConverter/NameCorrectVisitor.cs b/LanguagePlugins/SPython/SyntaxTreeConverters/SPythonStandardTreeConverter/NameCorrectVisitor.cs index d0f240eca..4b1bda1f1 100644 --- a/LanguagePlugins/SPython/SyntaxTreeConverters/SPythonStandardTreeConverter/NameCorrectVisitor.cs +++ b/LanguagePlugins/SPython/SyntaxTreeConverters/SPythonStandardTreeConverter/NameCorrectVisitor.cs @@ -7,7 +7,7 @@ namespace Languages.SPython.Frontend.Converters { public HashSet variablesUsedAsGlobal = new HashSet(); - public NameCorrectVisitor(Dictionary> namesFromUsedUnits, HashSet definedFunctionsNames) : base(namesFromUsedUnits) + public NameCorrectVisitor(Dictionary> namesFromUsedUnits, HashSet definedFunctionsNames) : base(namesFromUsedUnits) { foreach (string definedFunctionName in definedFunctionsNames) { @@ -60,7 +60,8 @@ namespace Languages.SPython.Frontend.Converters switch (nameType) { case NameKind.GlobalVariable: - case NameKind.ImportedNameAlias: + case NameKind.ImportedVariableAlias: + case NameKind.ImportedNotVariableAlias: break; case NameKind.Unknown: throw new SPythonSyntaxVisitorError("UNKNOWN_NAME_{0}", @@ -91,7 +92,8 @@ namespace Languages.SPython.Frontend.Converters id.name = symbolTable.AliasToRealName(id.name); break; - case NameKind.ImportedNameAlias: + case NameKind.ImportedVariableAlias: + case NameKind.ImportedNotVariableAlias: _named_type_reference.names.Insert(0, new ident(symbolTable.AliasToModuleName(id.name), id.source_context)); _named_type_reference.names[1].name = symbolTable.AliasToRealName(_named_type_reference.names[1].name); break; @@ -114,7 +116,8 @@ namespace Languages.SPython.Frontend.Converters switch (nameKind) { - case NameKind.ImportedNameAlias: + case NameKind.ImportedVariableAlias: + case NameKind.ImportedNotVariableAlias: _named_type_reference.names.Insert(0, new ident(symbolTable.AliasToModuleName(fullName), _named_type_reference.names[0].source_context)); _named_type_reference.names[1].name = symbolTable.AliasToRealName(fullName); break; @@ -135,7 +138,8 @@ namespace Languages.SPython.Frontend.Converters _ident.name = symbolTable.AliasToRealName(_ident.name); break; - case NameKind.ImportedNameAlias: + case NameKind.ImportedVariableAlias: + case NameKind.ImportedNotVariableAlias: Replace(_ident, new dot_node(new ident(symbolTable.AliasToModuleName(_ident.name), sc) , new ident(symbolTable.AliasToRealName(_ident.name), sc), sc)); break; diff --git a/LanguagePlugins/SPython/SyntaxTreeConverters/SPythonStandardTreeConverter/SymbolTableFillingVisitor.cs b/LanguagePlugins/SPython/SyntaxTreeConverters/SPythonStandardTreeConverter/SymbolTableFillingVisitor.cs index b94fe8304..f29734ffd 100644 --- a/LanguagePlugins/SPython/SyntaxTreeConverters/SPythonStandardTreeConverter/SymbolTableFillingVisitor.cs +++ b/LanguagePlugins/SPython/SyntaxTreeConverters/SPythonStandardTreeConverter/SymbolTableFillingVisitor.cs @@ -10,7 +10,7 @@ namespace Languages.SPython.Frontend.Converters { protected SymbolTable symbolTable; - public SymbolTableFillingVisitor(Dictionary> par) { + public SymbolTableFillingVisitor(Dictionary> par) { symbolTable = new SymbolTable(par); } @@ -164,18 +164,20 @@ namespace Languages.SPython.Frontend.Converters if (_from_import_statement.is_star) { - foreach (string name in symbolTable.ModuleNameToSymbols[module_name]) - symbolTable.AddAlias(name, name, module_name); + foreach (var kv in symbolTable.ModuleNameToSymbols[module_name]) + symbolTable.AddAlias(kv.Key, kv.Value, kv.Key, module_name); } else { foreach (as_statement as_Statement in _from_import_statement.imported_names.as_statements) { - if (!symbolTable.ModuleNameToSymbols[module_name].Contains(as_Statement.real_name.name)) + var namesDict = symbolTable.ModuleNameToSymbols[module_name]; + + if (!namesDict.ContainsKey(as_Statement.real_name.name)) throw new SPythonSyntaxVisitorError("MODULE_{0}_HAS_NO_NAME_{1}", _from_import_statement.source_context, module_real_name, as_Statement.real_name.name); - symbolTable.AddAlias(as_Statement.real_name.name, as_Statement.alias.name, module_name); + symbolTable.AddAlias(as_Statement.real_name.name, namesDict[as_Statement.real_name.name], as_Statement.alias.name, module_name); } } } @@ -196,21 +198,23 @@ namespace Languages.SPython.Frontend.Converters protected enum NameKind { // Имя отсутствует в текущем контексте - Unknown = 0b_0000_0000, + Unknown = 0b_0000_0000, // Ключевые слова языка - Keyword = 0b_0000_0001, + Keyword = 0b_0000_0001, // Имя глобальной переменной - GlobalVariable = 0b_0000_0010, + GlobalVariable = 0b_0000_0010, // Имя глобальной функции - GlobalFunction = 0b_0000_0100, - // Имя подключённого модуля или его псевдоним - ModuleAlias = 0b_0000_1000, - // Имя, подключённое из модуля, или его псевдоним - ImportedNameAlias = 0b_0001_0000, + GlobalFunction = 0b_0000_0100, + // Имя подключённого модуля или его псевдоним + ModuleAlias = 0b_0000_1000, + // Имя, подключённое из модуля (не переменная или константа), или его псевдоним + ImportedNotVariableAlias = 0b_0001_0000, + // Подключенная из модуля константа или переменная + ImportedVariableAlias = 0b_0010_0000, // Локальня переменная - LocalVariable = 0b_0010_0000, + LocalVariable = 0b_0100_0000, // Имя глобальной forward-объявленной функции - ForwardDeclaredFunction = 0b_0100_0000, + ForwardDeclaredFunction = 0b_1000_0000, } protected class SymbolTable @@ -230,7 +234,7 @@ namespace Languages.SPython.Frontend.Converters nameTypes.Add(keyword, NameKind.Keyword); } - public SymbolTable(Dictionary> par) + public SymbolTable(Dictionary> par) { ModuleNameToSymbols = par; FillKeywords(); @@ -275,9 +279,9 @@ namespace Languages.SPython.Frontend.Converters private LocalScope localVariables = new LocalScope(); // moduleRealName -> functions and global variables in this module real names - private Dictionary> moduleNameToSymbols; + private Dictionary> moduleNameToSymbols; - public Dictionary> ModuleNameToSymbols + public Dictionary> ModuleNameToSymbols { get => moduleNameToSymbols; set @@ -289,8 +293,8 @@ namespace Languages.SPython.Frontend.Converters foreach (string standardLibrary in StandardLibraries) { if (moduleNameToSymbols.ContainsKey(standardLibrary)) - foreach (string name in moduleNameToSymbols[standardLibrary]) - AddAlias(name, name, standardLibrary); + foreach (var kv in moduleNameToSymbols[standardLibrary]) + AddAlias(kv.Key, kv.Value, kv.Key, standardLibrary); } } @@ -315,10 +319,11 @@ namespace Languages.SPython.Frontend.Converters public bool IsVisibleToAssign(string name) { NameKind kind = this[name]; - if (kind == NameKind.Unknown) return false; + if (kind == NameKind.Unknown || kind == NameKind.ImportedNotVariableAlias) return false; + if (!isInFunctionBody) return true; return (kind != NameKind.GlobalVariable && - kind != NameKind.ImportedNameAlias) || + kind != NameKind.ImportedVariableAlias) || NamesAddedByGlobal.Contains(name); } @@ -363,12 +368,12 @@ namespace Languages.SPython.Frontend.Converters else nameTypes.Add(name, nameType); } - public void AddAlias(string realName, string alias, string moduleName) + public void AddAlias(string realName, bool isVariable, string alias, string moduleName) { if (aliasToRealNameAndModuleName.ContainsKey(alias)) aliasToRealNameAndModuleName[alias] = Tuple.Create(realName, moduleName); else aliasToRealNameAndModuleName.Add(alias, Tuple.Create(realName, moduleName)); - AddGlobalName(alias, NameKind.ImportedNameAlias); + AddGlobalName(alias, isVariable ? NameKind.ImportedVariableAlias : NameKind.ImportedNotVariableAlias); } public void AddModuleAlias(string realName, string alias) diff --git a/ParserTools/ParserTools/BaseLanguageInformation.cs b/ParserTools/ParserTools/BaseLanguageInformation.cs index 07e63f331..ed7d7d2e5 100644 --- a/ParserTools/ParserTools/BaseLanguageInformation.cs +++ b/ParserTools/ParserTools/BaseLanguageInformation.cs @@ -44,6 +44,8 @@ namespace PascalABCCompiler.Parsers public abstract string ProcedureName { get; } public abstract string FunctionName { get; } + public abstract bool SyntaxTreeIsConvertedAfterUsedModulesCompilation { get; } + public abstract bool ApplySyntaxTreeConvertersForIntellisense { get; } public abstract bool IncludeDotNetEntities { get; } diff --git a/ParserTools/ParserTools/ILanguageInformation.cs b/ParserTools/ParserTools/ILanguageInformation.cs index 16db69a16..45f0195d9 100644 --- a/ParserTools/ParserTools/ILanguageInformation.cs +++ b/ParserTools/ParserTools/ILanguageInformation.cs @@ -170,6 +170,11 @@ namespace PascalABCCompiler.Parsers int FindParamDelimForIndexer(string descriptionAfterOpeningParenthesis, int number); + /// + /// Нужно ли вызывать конверторы синтаксического дерева, срабатывающие после компиляции зависимостей + /// + bool SyntaxTreeIsConvertedAfterUsedModulesCompilation { get; } + /// /// Вызывать ли преобразователей синтаксического дерева в работе Intellisense /// diff --git a/PascalABCLanguageInfo/PascalABCLanguageInformation.cs b/PascalABCLanguageInfo/PascalABCLanguageInformation.cs index 62d8654e7..26fe04242 100644 --- a/PascalABCLanguageInfo/PascalABCLanguageInformation.cs +++ b/PascalABCLanguageInfo/PascalABCLanguageInformation.cs @@ -26,6 +26,8 @@ namespace Languages.Pascal.Frontend.Data public override string[] SystemUnitNames => StringConstants.pascalDefaultStandardModules; + public override bool SyntaxTreeIsConvertedAfterUsedModulesCompilation => false; + public override bool ApplySyntaxTreeConvertersForIntellisense => false; protected IParser Parser diff --git a/SyntaxVisitors/CompilationArtifactsUsedBySyntaxConverters.cs b/SyntaxVisitors/CompilationArtifactsUsedBySyntaxConverters.cs index c58b897dd..12e2eb57f 100644 --- a/SyntaxVisitors/CompilationArtifactsUsedBySyntaxConverters.cs +++ b/SyntaxVisitors/CompilationArtifactsUsedBySyntaxConverters.cs @@ -6,11 +6,11 @@ namespace PascalABCCompiler { public struct CompilationArtifactsUsedBySyntaxConverters { - public CompilationArtifactsUsedBySyntaxConverters(Dictionary> namesFromUsedUnits) + public CompilationArtifactsUsedBySyntaxConverters(Dictionary> namesFromUsedUnits) { NamesFromUsedUnits = namesFromUsedUnits; } - public Dictionary> NamesFromUsedUnits { get; } + public Dictionary> NamesFromUsedUnits { get; } } }