Исправление переменных с именем, совпадающим с именами сущностей из других модулей, в SPython (#3360)
* 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
This commit is contained in:
parent
c54412c8aa
commit
4e871c1f3a
|
|
@ -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<string, HashSet<string>> CollectNamesFromUsedUnits(SymScope currentUnitScope)
|
||||
private Dictionary<string, Dictionary<string, bool>> CollectNamesFromUsedUnits(SymScope currentUnitScope)
|
||||
{
|
||||
var namesFromUsedUnits = new Dictionary<string, HashSet<string>>();
|
||||
var namesFromUsedUnits = new Dictionary<string, Dictionary<string, bool>>();
|
||||
|
||||
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<string>());
|
||||
namesFromUsedUnits.Add(unitScope.Name, new Dictionary<string, bool>());
|
||||
|
||||
foreach (var symbol in unitScope.symbol_table)
|
||||
{
|
||||
var scopesOrScope = ((DictionaryEntry)symbol).Value;
|
||||
|
||||
string name;
|
||||
bool isVariable;
|
||||
|
||||
if (scopesOrScope is List<SymScope> 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|||
|
||||
/// <summary>
|
||||
/// Глобальные имена сущностей из зависимостей интерфейсной части
|
||||
/// Внешний словарь по имени модуля выдает словарь сущностей.
|
||||
/// Внутренний словарь по имени сущности выдает флаг о том, является ли она переменной.
|
||||
/// </summary>
|
||||
public Dictionary<string, HashSet<string>> NamesFromUsedUnits { get; } = new Dictionary<string, HashSet<string>>();
|
||||
public Dictionary<string, Dictionary<string, bool>> NamesFromUsedUnits { get; } = new Dictionary<string, Dictionary<string, bool>>();
|
||||
|
||||
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<string>());
|
||||
foreach (var names in (unit.SemanticTree as common_unit_node).scope.Symbols.DictCaseSensitive.Skip(1))
|
||||
currentUnit.NamesFromUsedUnits.Add(unitName, new Dictionary<string, bool>());
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ namespace Languages.SPython.Frontend.Converters
|
|||
{
|
||||
public HashSet<string> variablesUsedAsGlobal = new HashSet<string>();
|
||||
|
||||
public NameCorrectVisitor(Dictionary<string, HashSet<string>> namesFromUsedUnits, HashSet<string> definedFunctionsNames) : base(namesFromUsedUnits)
|
||||
public NameCorrectVisitor(Dictionary<string, Dictionary<string, bool>> namesFromUsedUnits, HashSet<string> 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;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace Languages.SPython.Frontend.Converters
|
|||
{
|
||||
protected SymbolTable symbolTable;
|
||||
|
||||
public SymbolTableFillingVisitor(Dictionary<string, HashSet<string>> par) {
|
||||
public SymbolTableFillingVisitor(Dictionary<string, Dictionary<string, bool>> 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<string, HashSet<string>> par)
|
||||
public SymbolTable(Dictionary<string, Dictionary<string, bool>> 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<string, HashSet<string>> moduleNameToSymbols;
|
||||
private Dictionary<string, Dictionary<string, bool>> moduleNameToSymbols;
|
||||
|
||||
public Dictionary<string, HashSet<string>> ModuleNameToSymbols
|
||||
public Dictionary<string, Dictionary<string, bool>> 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)
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -170,6 +170,11 @@ namespace PascalABCCompiler.Parsers
|
|||
|
||||
int FindParamDelimForIndexer(string descriptionAfterOpeningParenthesis, int number);
|
||||
|
||||
/// <summary>
|
||||
/// Нужно ли вызывать конверторы синтаксического дерева, срабатывающие после компиляции зависимостей
|
||||
/// </summary>
|
||||
bool SyntaxTreeIsConvertedAfterUsedModulesCompilation { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Вызывать ли преобразователей синтаксического дерева в работе Intellisense
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ namespace PascalABCCompiler
|
|||
{
|
||||
public struct CompilationArtifactsUsedBySyntaxConverters
|
||||
{
|
||||
public CompilationArtifactsUsedBySyntaxConverters(Dictionary<string, HashSet<string>> namesFromUsedUnits)
|
||||
public CompilationArtifactsUsedBySyntaxConverters(Dictionary<string, Dictionary<string, bool>> namesFromUsedUnits)
|
||||
{
|
||||
NamesFromUsedUnits = namesFromUsedUnits;
|
||||
}
|
||||
|
||||
public Dictionary<string, HashSet<string>> NamesFromUsedUnits { get; }
|
||||
public Dictionary<string, Dictionary<string, bool>> NamesFromUsedUnits { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue