pascalabcnet/TreeConverter/SymbolTable/DSST/SymbolTable.cs
Александр Земляк c69daac622
Рефакторинг таблицы символов, чтобы заполнялся только один словарь (#3417)
* Refactor SymbolTable to improve architecture

* Fix PABCSystem function calls in SPython standard modules

* Fix names search in SymbolTable and CollectNamesFromUsedUnits in Compiler

* Add SemanticRulesConstants.SymbolTableCaseSensitive setting in pcu reader

* Fix case sensitive search in DSSymbolTable class

* Add case sensitive search test cases for SPython

* Leave only one dictionary in SymbolsDictionary class

* Refactor Find function in SymbolsDictionary

* Fix math.pys module

* Fix str.pys

* Imrove Find method in SymbolsDictionary

* DefaultIfEmpty was wrong - need to use Any()
2026-04-06 22:41:26 +03:00

1322 lines
54 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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.Linq;
using PascalABCCompiler.TreeConverter;
using System.Collections.Generic;
using SymbolTable;
using System.Reflection;
using static PascalABCCompiler.TreeConverter.SemanticRulesConstants;
namespace PascalABCCompiler.TreeRealization
{
public abstract class BasePCUReader
{
public abstract definition_node CreateInterfaceMember(int offset, string name);
public static void RestoreSymbolsInterfaceMember(List<SymbolInfo> sil, string name)
{
if (sil != null)
{
foreach (var si in sil)
{
if (si.sym_info != null)
if (si.sym_info.semantic_node_type == semantic_node_type.wrap_def)
{
wrapped_definition_node wdn = (wrapped_definition_node)si.sym_info;
si.sym_info = wdn.PCUReader.CreateInterfaceMember(wdn.offset, name);
}
}
}
}
public abstract definition_node CreateInterfaceInClassMember(int offset, string name);
public abstract definition_node CreateImplementationMember(int offset, bool restore_code=true);
public abstract definition_node CreateTypeSynonim(int offset, string name);
public static void RestoreSymbol(SymbolInfo si, string name, int index = 0)
{
if (si != null)
{
if (si.sym_info != null)
{
if (si.sym_info.semantic_node_type == semantic_node_type.wrap_def)
{
wrapped_definition_node wdn = (wrapped_definition_node)si.sym_info;
RestoreSymbols(si, wdn, name);
}
}
}
}
public static void RestoreSymbols(List<SymbolInfo> sil, string name, int index = 0)
{
if (sil != null)
{
for (int i = index; i < sil.Count; ++i)
{
if (sil[i].sym_info != null)
if (sil[i].sym_info.semantic_node_type == semantic_node_type.wrap_def)
{
wrapped_definition_node wdn = (wrapped_definition_node)sil[i].sym_info;
RestoreSymbols(sil[i], wdn, name);
}
}
}
}
static void RestoreSymbols(SymbolInfo si, wrapped_definition_node wdn, string name)
{
if (wdn.is_synonim)
si.sym_info = wdn.PCUReader.CreateTypeSynonim(wdn.offset, name);
else
if (si.scope is ClassScope)
si.sym_info = wdn.PCUReader.CreateInterfaceInClassMember(wdn.offset, name);
else
si.sym_info = wdn.PCUReader.CreateImplementationMember(wdn.offset, false);
}
}
/*public class PCUReturner
{
private static Hashtable ht = new Hashtable();
public static void Clear()
{
ht.Clear();
}
public static BasePCUReader GetPCUReader(PascalABCCompiler.TreeRealization.wrapped_definition_node wdn)
{
return (BasePCUReader)ht[wdn];
}
public static void AddPCUReader(PascalABCCompiler.TreeRealization.wrapped_definition_node wdn, BasePCUReader pr)
{
ht[wdn] = pr;
}
}*/
public class wrapped_definition_node : definition_node
{
public int offset;
public bool is_synonim;
public BasePCUReader PCUReader;
public wrapped_definition_node(int offset, BasePCUReader PCUReader)
{
this.offset = offset;
this.PCUReader = PCUReader;
}
public override general_node_type general_node_type
{
get
{
return general_node_type.unit_node;
}
}
public override semantic_node_type semantic_node_type
{
get
{
return semantic_node_type.wrap_def;
}
}
}
}
namespace SymbolTable
{
#region SymbolTableConstants набор констант определяющих поведение таблицы символов
public class SymbolTableConstants
{
//стартовый размер списка информаций о символах
public const int InfoList_StartSize=1;
//рекомендуемый стартовый размер хештаблицы
public const int HashTable_StartSize=8192;
//параметры поведения хеш таблицы
public const int HashTable_StartResise=85; //Расширить хеш на ProcResize процентов,
public const int HashTable_ProcResize =100;//если он заполнен на StartResize процентов
public const int SymbolNotFound=-1;
}
#endregion
#region Scope,DotNETScope,UnitPartScope,UnitInterfaceScope,UnitImplementationScope,ClassScope элемены таблицы областей видимости
//элемент таблицы областей видимости
//при создании добавляет себя в vSymbolTable
public class Scope // :BaseScope
{
public string Name;
public override string ToString() => Name == ""? GetType().Name : Name;
public SymbolsDictionary Symbols;
public List<Scope> InternalScopes;
public DSSymbolTable SymbolTable;
public bool CaseSensitive;
public bool AddStatementsToFront = false; // SSM - введено для необходимости добавлять statements не только в конец statement_list, но и в начало. Нужно для синтаксически сахарных конструкций: например, для создания объекта класса при замыканиях
public Scope TopScope;
public int ScopeNum;
public StringComparison StringComparison => CaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
public Scope(DSSymbolTable vSymbolTable, Scope TopScope, string Name)
{
SymbolTable=vSymbolTable;
this.TopScope = null;
if (TopScope != null) {
this.TopScope = TopScope;
TopScope.InternalScopes.Add(this);
}
this.Name = Name;
ScopeNum = SymbolTable.GetNewScopeNum();
SymbolTable.ScopeTable.Add(this);
CaseSensitive = SemanticRulesConstants.SymbolTableCaseSensitive;
Symbols = new SymbolsDictionary();
InternalScopes = new List<Scope>();
}
public Scope(DSSymbolTable vSymbolTable, Scope TopScope, bool CaseSensitive)
{
SymbolTable = vSymbolTable;
this.TopScope = null;
if (TopScope != null)
{
this.TopScope = TopScope;
TopScope.InternalScopes.Add(this);
}
ScopeNum = SymbolTable.GetNewScopeNum();
SymbolTable.ScopeTable.Add(this);
this.CaseSensitive = CaseSensitive;
Symbols = new SymbolsDictionary();
InternalScopes = new List<Scope>();
}
public void ClearScope()
{
foreach (var sc in InternalScopes)
sc.ClearScope();
Symbols.ClearTable();
}
public virtual List<SymbolInfo> Find(string name)
{
return Find(name, null);
}
public virtual List<SymbolInfo> Find(string name, Scope CurrentScope)
{
List<SymbolInfo> sil = SymbolTable.Find(this, name, CurrentScope);
if (sil == null) return sil;
PascalABCCompiler.TreeRealization.BasePCUReader.RestoreSymbols(sil, name);
return sil;
}
public virtual List<SymbolInfo> FindOnlyInScopeAndBlocks(string name)
{
return SymbolTable.FindOnlyInScope(this, name, true);
}
public virtual List<SymbolInfo> FindOnlyInScope(string name)
{
return SymbolTable.FindOnlyInScope(this, name, false);
}
public virtual List<SymbolInfo> FindOnlyInType(string name, Scope CurrentScope)
{
List<SymbolInfo> sil = SymbolTable.FindOnlyInType(this, name, CurrentScope);
if (sil == null) return sil;
PascalABCCompiler.TreeRealization.BasePCUReader.RestoreSymbols(sil, name);
return sil;
}
public void AddSymbol(string Name, SymbolInfo Inf)
{
SymbolTable.Add(this, Name, Inf);
Inf.Name = Name;
}
/// <summary>
/// Получить информацию обо всех символах скоупа
/// </summary>
public IEnumerable<HashTableNode> GetAllSymbolInfos() => Symbols.GetAllSymbolInfos();
}
public class BlockScope : Scope
{
public BlockScope(DSSymbolTable vSymbolTable, Scope TopScope)
: base(vSymbolTable, TopScope, "")
{
}
}
public class LambdaScope : Scope //lroman//
{
public LambdaScope(DSSymbolTable vSymbolTable, Scope TopScope)
: base(vSymbolTable, TopScope, "")
{
}
}
public class WithScope : BlockScope
{
public Scope[] WithScopes;
public WithScope(DSSymbolTable vSymbolTable, Scope TopScope, Scope[] WithScopes)
: base(vSymbolTable, TopScope)
{
this.WithScopes = WithScopes;
}
}
public class DotNETScope:Scope
{
public NamespaceScope AdditionalNamespaceScope;
public DotNETScope(DSSymbolTable vSymbolTable):base(vSymbolTable,null,false)
{
}
}
public class UnitPartScope:Scope
{
public Scope[] TopScopeArray;
public UnitPartScope(DSSymbolTable vSymbolTable,Scope TopScope,Scope[] vTopScopeArray, string Name):
base(vSymbolTable,TopScope, Name)
{
TopScopeArray=vTopScopeArray;
}
}
public class UnitInterfaceScope:UnitPartScope
{
public UnitInterfaceScope(DSSymbolTable vSymbolTable,Scope TopScope,Scope[] vTopScopeArray, string Name):
base(vSymbolTable, TopScope, vTopScopeArray, Name)
{
}
}
public class UnitImplementationScope:UnitPartScope
{
public UnitImplementationScope(DSSymbolTable vSymbolTable, Scope TopScope, Scope[] vTopScopeArray, string Name)
:
base(vSymbolTable, TopScope, vTopScopeArray, Name)
{}
}
public class NamespaceScope: UnitInterfaceScope
{
public NamespaceScope(DSSymbolTable vSymbolTable, Scope TopScope, Scope[] vTopScopeArray, string Name):
base(vSymbolTable, TopScope, vTopScopeArray, Name)
{
}
}
public class ClassScope:Scope
{
public ClassScope PartialScope;
public PascalABCCompiler.TreeRealization.common_type_node class_type = null;
// SSM 02.04.19 - буду присваивать это поле только для создаваемых пользователем классов. Понадобилось для доступа к членам NET-класса из его потомка - обычного класса
public Scope BaseClassScope;
public ClassScope(DSSymbolTable vSymbolTable,Scope TopScope,Scope BaseClassScope, string Name):
base(vSymbolTable,TopScope, Name)
{
this.BaseClassScope = null;
if (BaseClassScope != null)
this.BaseClassScope = BaseClassScope;
}
public override List<SymbolInfo> Find(string name, Scope CurrentScope)
{
List<SymbolInfo> si_list = SymbolTable.Find(this, name, CurrentScope);
if (PartialScope != null)
{
if (si_list == null)
si_list = SymbolTable.Find(PartialScope, name, CurrentScope);
else
{
var sil = SymbolTable.Find(PartialScope, name, CurrentScope);
if(sil != null)
si_list.AddRange(sil);
}
}
if (si_list == null) return si_list;
PascalABCCompiler.TreeRealization.BasePCUReader.RestoreSymbols(si_list, name);
return si_list;
}
public override List<SymbolInfo> FindOnlyInType(string name, Scope CurrentScope)
{
List<SymbolInfo> sil = SymbolTable.FindOnlyInType(this, name, CurrentScope);
if (PartialScope != null)
{
if (sil == null)
sil = SymbolTable.FindOnlyInType(PartialScope, name, CurrentScope);
else
{
var temp_sil = SymbolTable.FindOnlyInType(PartialScope, name, CurrentScope);
if(temp_sil != null)
sil.AddRange(temp_sil);
}
}
if (sil == null) return sil;
PascalABCCompiler.TreeRealization.BasePCUReader.RestoreSymbols(sil, name);
return sil;
}
}
/*public class GenericTypeInstanceScope : ClassScope
{
private PascalABCCompiler.TreeRealization.generic_instance_type_node _instance_type;
private Scope _orig_scope;
public GenericTypeInstanceScope(PascalABCCompiler.TreeRealization.generic_instance_type_node instance_type,
Scope orig_scope, Scope BaseClassScope)
: base(orig_scope.SymbolTable, orig_scope.TopScope, BaseClassScope)
{
_orig_scope = orig_scope;
_instance_type = instance_type;
}
public override SymbolInfoList Find(string name)
{
return _instance_type.ConvertSymbolInfo(_orig_scope.Find(name));
}
public override SymbolInfoList Find(string name, Scope CurrentScope)
{
return _instance_type.ConvertSymbolInfo(_orig_scope.Find(name, CurrentScope));
}
public override SymbolInfoList FindOnlyInScope(string name)
{
return _instance_type.ConvertSymbolInfo(_orig_scope.FindOnlyInScope(name));
}
public override SymbolInfoList FindOnlyInScopeAndBlocks(string name)
{
return _instance_type.ConvertSymbolInfo(_orig_scope.FindOnlyInScopeAndBlocks(name));
}
}*/
//(ssyy) Интерфейс для интерфейсов
public interface IInterfaceScope
{
Scope[] TopInterfaceScopeArray
{
get;
set;
}
}
//ssyy owns
//Область видимости для интерфейсов
//Наследование от ClassScope сделано для простоты, так как в кодах
//местами есть проверки (scope is ClassScope)
public class InterfaceScope : ClassScope, IInterfaceScope
{
private Scope[] _TopInterfaceScopeArray;
public virtual Scope[] TopInterfaceScopeArray
{
get
{
return _TopInterfaceScopeArray;
}
set
{
_TopInterfaceScopeArray = value;
}
}
public InterfaceScope(DSSymbolTable vSymbolTable, Scope TopScope, Scope[] vTopInterfaceScopeArray, string Name)
:
base(vSymbolTable, TopScope, null, Name)
{
_TopInterfaceScopeArray = vTopInterfaceScopeArray;
}
public InterfaceScope(DSSymbolTable vSymbolTable, Scope TopScope, Scope BaseClassScope, Scope[] vTopInterfaceScopeArray, string Name)
:
base(vSymbolTable, TopScope, BaseClassScope, Name)
{
_TopInterfaceScopeArray = vTopInterfaceScopeArray;
}
}
//\ssyy owns
//В ClassMethodScope TopScope должен быть классом
public class ClassMethodScope:Scope
{
public Scope DefScope;
// aab 26.04.19 Добавил для исправления захвата переменных в лямбде
// Для лямбды нужен обратный порядок поиска звхваченных переменных: сначала в месте определения, потом в классе
public Scope CurrentLambdaDefScope;
public ClassMethodScope(DSSymbolTable vSymbolTable, Scope TopScope, Scope DefScope, Scope CurrentLambdaDefScope, string Name):
base(vSymbolTable,TopScope, Name)
{
this.Name = Name;
this.DefScope = null;
if (DefScope != null)
this.DefScope = DefScope;
this.CurrentLambdaDefScope = CurrentLambdaDefScope;
}
}
#endregion
#region HashTableNode элемент хеш-таблицы
public class HashTableNode
{
public List<SymbolInfo> InfoList;
public HashTableNode()
{
InfoList = new List<SymbolInfo>(SymbolTableConstants.InfoList_StartSize);
}
public HashTableNode(List<SymbolInfo> infoList)
{
InfoList = infoList;
}
public override string ToString()
{
System.Text.StringBuilder str = new System.Text.StringBuilder();
foreach (var sym in InfoList)
str.Append(sym.ToString() + ";");
return str.ToString();
}
}
#endregion
#region Для отображения таблицы символов в отладке
public class LightSymbolnfo
{
public PrimaryScope inner_scope
{
get
{
if (information.sym_info is PascalABCCompiler.TreeRealization.common_function_node)
{
var temp = information.sym_info as PascalABCCompiler.TreeRealization.common_function_node;
if (temp.scope != null)
return new PrimaryScope(temp.scope);
}
else if (information.sym_info is PascalABCCompiler.TreeRealization.type_node)
{
var temp = information.sym_info as PascalABCCompiler.TreeRealization.type_node;
if (temp.Scope != null)
return new PrimaryScope(temp.Scope);
}
return null;
}
}
public SymbolInfo information;
public override string ToString() => information.ToString();
public LightSymbolnfo(SymbolInfo si)
{
information = si;
}
}
public class LightScopeNode
{
public List<LightSymbolnfo> Overloads = new List<LightSymbolnfo>();
public override string ToString()
{
System.Text.StringBuilder str = new System.Text.StringBuilder();
foreach (var sym in Overloads)
str.Append(sym.ToString() + ";");
return str.ToString();
}
}
public class PrimaryScope
{
public List<PrimaryScope> SubScopes
{
get
{
var subScopes = new List<PrimaryScope>();
foreach (var sub_sc in real_scope.InternalScopes)
subScopes.Add(new PrimaryScope(sub_sc));
return subScopes;
}
}
/*public List<LightScopeNode> Symbols
{
get
{
var symbols = new List<LightScopeNode>();
foreach (var sy in real_scope.Symbols.dictCaseSensitive)
{
LightScopeNode res = new LightScopeNode();
foreach (var sy_overload in sy.Value.InfoList)
res.Overloads.Add(new LightSymbolnfo(sy_overload));
symbols.Add(res);
}
return symbols;
}
}*/
public string ScopeName;
public override string ToString() => ScopeName == "" ? GetType().Name : ScopeName;
private Scope real_scope;
public PrimaryScope(Scope sc)
{
real_scope = sc;
if(real_scope is BlockScope)
{
int deep = 0;
Scope Top = real_scope.TopScope;
while(Top != null && (Top is BlockScope))
{
deep++;
Top = Top.TopScope;
}
ScopeName = "Begin—End;(Deep = " + deep + ")";
}
else
ScopeName = sc.Name;
}
}
#endregion
// Определения
// ОВ - область видимости
// ООВ - особая область видимости в стиле delphi.это:
// - ОВ поцедуры
// - OВ класса + ОВ предков
// - ОВ модуля + ОВ интерфейсных частей всех модулей подклюценных к нему
public class DSSymbolTable
{
public List<Scope> ScopeTable;
private Scope CurrentScope;
private int ScopeIndex = -1;
/*public override string ToString()
{
var sb = new System.Text.StringBuilder();
var a = ScopeTable.SkipWhile(s => !(s.GetType() == typeof(UnitInterfaceScope))).Skip(1).SkipWhile(s => !(s.GetType() == typeof(UnitInterfaceScope)));
var globscopenum = a.First().ScopeNum;
var d = new Dictionary<Scope, List<Tuple<string, SymbolInfo>>>();
foreach (var x in a)
{
sb.Append(x.ToString() + "\n");
//d[x.ScopeNum] = x;
}
foreach (var x in HashTable.dict)
{
foreach (var y in x.Value.NumAreaList.data.Take(x.Value.NumAreaList.Count))
{
foreach (var z in y.InfoList)
{
if (z.scope.ScopeNum >= globscopenum)
{
if (!d.ContainsKey(z.scope))
d[z.scope] = new List<Tuple<string, SymbolInfo>>();
d[z.scope].Add(new Tuple<string, SymbolInfo>(x.Key, z));
}
}
}
}
sb.Append("\n");
foreach (var x in d.OrderBy(x => x.Key.ScopeNum))
{
sb.Append(x.Key.ScopeNum + "—>" + x.Key.TopScopeNum + "\n");
foreach (var y in x.Value)
{
sb.Append(" " + y.Item1 + ": " + y.Item2.sym_info.ToString() + "\n");
}
}
return sb.ToString();
}*/
#region DSSymbolTable(int hash_size,bool case_sensitive)
public DSSymbolTable(int hash_size)
{
Clear();
}
#endregion
#region Clear() очистка таблицы
public void Clear()
{
ScopeTable = new List<Scope>();
ScopeIndex = -1;
}
#endregion
#region CreateScope для различных Scope
public LambdaScope CreateLambdaScope(Scope TopScope) //lroman//
{
return new LambdaScope(this, TopScope);
}
public Scope CreateScope(Scope TopScope, string Name = "")
{
return new Scope(this, TopScope, Name);
}
public ClassScope CreateClassScope(Scope TopScope,Scope BaseClass, string Name = "")
{
return new ClassScope(this, TopScope, BaseClass, Name);
}
//ssyy
public InterfaceScope CreateInterfaceScope(Scope TopScope, Scope[] TopInterfaces, string Name = "")
{
return new InterfaceScope(this, TopScope, TopInterfaces, Name);
}
public InterfaceScope CreateInterfaceScope(Scope TopScope, Scope BaseClass, Scope[] TopInterfaces, string Name = "")
{
return new InterfaceScope(this, TopScope, BaseClass, TopInterfaces, Name);
}
//\ssyy
public UnitInterfaceScope CreateUnitInterfaceScope(Scope[] UsedUnits, string Name = "")
{
return new UnitInterfaceScope(this, null, UsedUnits, Name);
}
public NamespaceScope CreateNamespaceScope(Scope[] UsedUnits, Scope TopScope, string Name = "")
{
return new NamespaceScope(this, TopScope, UsedUnits, Name);
}
public UnitImplementationScope CreateUnitImplementationScope(Scope InterfaceScope,Scope[] UsedUnits, string Name = "")
{
return new UnitImplementationScope(this, InterfaceScope, UsedUnits, Name);
}
public ClassMethodScope CreateClassMethodScope(Scope TopScope, Scope DefScope, Scope CurrentLambdaDefScope = null, string Name = "")
{
return new ClassMethodScope(this, TopScope, DefScope, CurrentLambdaDefScope, Name);
}
#endregion
//Возвращает количество уровней на которые надо поднятся начиная с Down чтобы очутиться в Up
//Работает только для процедур. Модуль считает за одно Scope
public int GetRelativeScopeDepth(Scope Up,Scope Down)
{
if (Up == Down) return 0;
int depth = 0;
while(Down.TopScope != null)
{
if (Up == Down) return depth;
if(!(Down is UnitImplementationScope))
depth++;
Down = Down.TopScope;
}
//throw new Exception("Can not execute st depth");
return -1;
}
//Добавление символа
//если такой символ в пр-ве имен уже существует то symbol_info добавляется к Symbols[].InfoList[]
public void Add(Scope InScope, string Name, SymbolInfo Inf)
{
Inf.scope = InScope;
InScope.Symbols.Add(Name, Inf);
// SSM 07.10.17 - переделал внутреннее представление HashTable на основе Dictionary
//if (hn == null)
// throw new Exception("Попытка добавить уже добавленное имя " + Name + " в HashTable. Обратитесь к разработчикам");
// hn.Name = Name;
// hn.InfoList.Add(Inf);
}
public void RemoveScope(Scope scope)
{
#if (DEBUG)
if (scope == null) throw new Exception("Ошибка при взятии верхней области видимости: область с номером " + scope + " не существует");
#endif
scope.ClearScope();
foreach (var in_scope in scope.InternalScopes)
ScopeTable.Remove(in_scope);
ScopeTable.Remove(scope);
if (scope.TopScope != null)
scope.TopScope.InternalScopes.Remove(scope);
}
// Пока что считаем, что caseaSensitiveSearch совпадает с SymbolTableCaseSensitive EVA
public List<SymbolInfo> FindOnlyInScope(Scope scope, string Name, bool FindInUpperBlocks) => FindOnlyInScope(scope, Name, FindInUpperBlocks, SymbolTableCaseSensitive);
//Этот метод ищет ТОЛЬКО В УКАЗАННОЙ ОВ, и не смотрит есть ли имя выше.
//Если это ОВ типа UnitImplementationScope то имя ищется также и
//в верней ОВ, которая типа UnitInterfaceScope
public List<SymbolInfo> FindOnlyInScope(Scope scope, string Name, bool FindInUpperBlocks, bool caseSensitiveSearch)
{
// if (!scope.CaseSensitive) Name = Name.ToLower();
CurrentScope = null;
List<SymbolInfo> Result = new List<SymbolInfo>();
if (scope is DotNETScope)//если нет такого ищем в областях .NET
{
AddToSymbolInfo(Result, (DotNETScope)scope, Name);
return Result.Count() > 0 ? Result : null;
}
Scope CurrentArea = scope, bs;
IEnumerable<SymbolInfo> infos;
do
{
if (CurrentArea is UnitPartScope) //мы очутились в модуле
{
//мы в ImplementationPart?
if (CurrentArea is UnitImplementationScope)
{
infos = CurrentArea.Symbols.Find(Name, caseSensitiveSearch);
if (infos != null) //что-то нашли!
AddToSymbolInfo(infos, Result);
CurrentArea = CurrentArea.TopScope;
}
//сейча мы в InterfacePart
infos = CurrentArea.Symbols.Find(Name, caseSensitiveSearch);
if (infos != null) //что-то нашли!
AddToSymbolInfo(infos, Result);
if (Result.Count() > 0)
return Result;
}
if (CurrentArea is WithScope)//мы очутились в With
{
infos = CurrentArea.Symbols.Find(Name, caseSensitiveSearch);
if (infos != null) //что-то нашли!
AddToSymbolInfo(infos, Result);
if (Result.Count() > 0) //если что-то нашли то заканчиваем
return Result;
FindAllInAreaList(Name, (CurrentArea as WithScope).WithScopes, true, true, Result, caseSensitiveSearch);
if (Result.Count() > 0) //если что-то нашли то заканчиваем
return Result;
}
else
{
infos = CurrentArea.Symbols.Find(Name, caseSensitiveSearch);
if (infos != null) //что-то нашли!
{
AddToSymbolInfo(infos, Result);
return Result.Count() > 0 ? Result : null;
}
}
bs = CurrentArea;
CurrentArea = CurrentArea.TopScope;
} while (CurrentArea != null && (FindInUpperBlocks && bs is BlockScope));
return null;
}
private void FindAllInClass(string name, Scope ClassArea, bool OnlyInThisClass, List<SymbolInfo> Result, bool caseSensitiveSearch)
{
IEnumerable<SymbolInfo> infos;
Scope ar = ClassArea;
if ((infos = ar.Symbols.Find(name, caseSensitiveSearch)) != null)
AddToSymbolInfo(infos, Result);
if (ar is DotNETScope)
{
PascalABCCompiler.TreeRealization.BasePCUReader.RestoreSymbols(Result, name);
AddToSymbolInfo(Result, (DotNETScope)ar, name);
return;
}
ClassScope cl = (ClassScope)ClassArea;
if (!OnlyInThisClass)
{
while (cl.BaseClassScope != null)
{
infos = cl.BaseClassScope.Symbols.Find(name, caseSensitiveSearch); // SSM 30/06/20 - надо исключать generis-параметры из поиска - их не существует в производном классе!!!
if (infos != null)
{
if (infos.First().sym_info is PascalABCCompiler.TreeRealization.common_type_node cctt && cctt.is_generic_parameter)
{
// пропустить!!!
}
else
{
AddToSymbolInfo(infos, Result);
}
}
ar = cl.BaseClassScope;
if (ar is DotNETScope)
{
AddToSymbolInfo(Result, (DotNETScope)ar, name);
return;
}
cl = (ClassScope)cl.BaseClassScope;
}
if (cl.BaseClassScope == null && cl.class_type.base_type is PascalABCCompiler.TreeRealization.compiled_type_node ctn)
{
var a = ctn.find(name);
if (a != null)
AddToSymbolInfo(a, Result);
return;
}
}
}
private Scope FindUnitInterfaceScope(Scope scope)
{
while (scope!=null && !(scope is UnitInterfaceScope))
scope = scope.TopScope;
return scope;
}
private Scope FindClassScope(Scope scope)
{
while (scope != null && !(scope is ClassScope))
/*if(scope is ClassMethodScope)
scope = scope.TopScope;
else*/ // PVS 01/2022
scope = scope.TopScope;
return scope;
}
private bool IsInOneModule(Scope Scope1, Scope Scope2)
{
Scope1 = FindUnitInterfaceScope(Scope1);
Scope2 = FindUnitInterfaceScope(Scope2);
return (Scope1 != null) && (Scope2 != null) && (Scope1 == Scope2);
}
private bool IsInOneOrDerivedClass(Scope IdentScope, Scope FromScope)
{
IdentScope = FindClassScope(IdentScope);
FromScope = FindClassScope(FromScope);
while (FromScope != null)
{
if (IdentScope == FromScope)
return true;
if (FromScope is ClassScope)
FromScope = ((ClassScope)FromScope).BaseClassScope;
else
FromScope = ((PascalABCCompiler.NetHelper.NetTypeScope)FromScope).TopScope;
}
return false;
}
private bool IsVisible(SymbolInfo ident, Scope fromScope)
{
if (fromScope == null)
return true;
if (FindClassScope(ident.scope) == null)
return true;
switch (ident.access_level)
{
case access_level.al_public:
case access_level.al_internal:
return true;
case access_level.al_protected:
return IsInOneModule(ident.scope, fromScope) || IsInOneOrDerivedClass(ident.scope, fromScope);
case access_level.al_private:
return IsInOneModule(ident.scope, fromScope);
}
return true;
}
private bool IsNormal(SymbolInfo to, SymbolInfo add)
{
return //true;
(to == null) || (to.scope == null) || ((to.scope != null) && //to.scope == null не нужно?
(((to.symbol_kind == symbol_kind.sk_none) && (add.symbol_kind == symbol_kind.sk_none)) && (to.scope == add.scope))
||
((to.symbol_kind == symbol_kind.sk_overload_function) && (add.symbol_kind == symbol_kind.sk_overload_function))
//|| // SSM 06.01.26 пробую разрешить конструктор вместе с функцией Create. Увы - select_function слаба - она только по параметрам пытается определить, а параметры у конструктора и функции Create одни и те же
//((to.symbol_kind == symbol_kind.sk_overload_function) && (add.sym_info is common_method_node cmn) && cmn.is_constructor)
||
((to.symbol_kind == symbol_kind.sk_overload_procedure) && (add.symbol_kind == symbol_kind.sk_overload_procedure))
|| to.sym_info != add.sym_info && (to.sym_info is PascalABCCompiler.TreeRealization.function_node || to.symbol_kind == symbol_kind.sk_overload_function) && add.sym_info is PascalABCCompiler.TreeRealization.function_node
/*&& (to.sym_info as PascalABCCompiler.TreeRealization.function_node).is_extension_method*/ && (add.sym_info as PascalABCCompiler.TreeRealization.function_node).is_extension_method
);
}
private void AddToSymbolInfo(IEnumerable<SymbolInfo> from, List<SymbolInfo> to)
{
bool CheckVisible = CurrentScope != null, NeedAdd = false;
SymbolInfo last_sym = to.LastOrDefault();
foreach (SymbolInfo si in from)
{
if (CheckVisible)
NeedAdd = IsVisible(si, CurrentScope) && IsNormal(last_sym, si);
else
NeedAdd = IsNormal(last_sym, si);
if (NeedAdd && to.IndexOf(si) == -1)
{
to.Add(si);
last_sym = si;
}
}
}
private void AddToSymbolInfo(List<SymbolInfo> to, DotNETScope ar, string name)
{
List<SymbolInfo> sil = ar.Find(name);
if (sil != null)
if (IsNormal(to.LastOrDefault(), sil.FirstOrDefault()))
to.AddRange(sil);
}
private void FindAllInAreaList(string name, Scope[] arr, bool need, List<SymbolInfo> Result, bool caseSensitiveSearch)
{
FindAllInAreaList(name, arr, false, need, Result, caseSensitiveSearch);
}
public void FindAllInAreaList(string name, Scope[] arr, bool StopIfFind, bool NotOnlyInNetScopes, List<SymbolInfo> Result, bool caseSensitiveSearch)
{
if (arr == null) return;
int add = Result.Count;
HashSet<Assembly> assm_cache = new HashSet<Assembly>();
foreach (Scope sc in arr)
{
if (sc is DotNETScope) // /*&& name.ToLower() != "pabcsystem"*/
{
if (sc is PascalABCCompiler.NetHelper.NetScope netScope)
{
if (PascalABCCompiler.NetHelper.NetHelper.PABCSystemType == null || netScope.Assembly != PascalABCCompiler.NetHelper.NetHelper.PABCSystemType.Assembly)
{
if (!assm_cache.Contains(netScope.Assembly))
assm_cache.Add(netScope.Assembly);
else if (netScope.used_namespaces.Count == 0)
continue;
}
}
var netScope1 = sc as PascalABCCompiler.NetHelper.NetScope;
var IsPABCSystemAssembly = false;
if (PascalABCCompiler.NetHelper.NetHelper.PABCSystemType != null && netScope1 != null && netScope1.Assembly == PascalABCCompiler.NetHelper.NetHelper.PABCSystemType.Assembly)
IsPABCSystemAssembly = true;
// не добавлять если это NetScope но не PABCSystemType.Assembly
if (IsPABCSystemAssembly || name.ToLower() != "pabcsystem")
AddToSymbolInfo(Result, (DotNETScope)sc, name);
if (Result.Count > add && StopIfFind)
return;
}
else
if (NotOnlyInNetScopes && sc != null)
{
var infos = sc.Symbols.Find(name, caseSensitiveSearch);
if (infos != null)
{
AddToSymbolInfo(infos, Result);
if (Result.Count > add && StopIfFind)
return;
}
}
}
}
//поиск всех имен в ООВ.
// ищет наборы имен в ООВ, если находит то возвращает их список.
// иначе ищет в обьемлющем ООВ.
//SymbolInfo возвращаются в поряде в котором они встретились при проходе областей
public List<SymbolInfo> Find(Scope scope, string Name)
{
return FindAll(scope, Name, false, false, null);
}
public List<SymbolInfo> Find(Scope scope, string Name, Scope FromScope)
{
return FindAll(scope, Name, false, false, FromScope);
}
public List<SymbolInfo> FindOnlyInType(Scope scope, string Name)
{
return FindAll(scope, Name, true, false, null);
}
public List<SymbolInfo> FindOnlyInType(Scope scope, string Name, Scope FromScope)
{
return FindAll(scope, Name, true, false, FromScope);
}
public List<SymbolInfo> FindOnlyInThisClass(ClassScope scope, string Name)
{
return FindAll(scope, Name, true, true, null);
}
// Пока что считаем, что caseaSensitiveSearch совпадает с SymbolTableCaseSensitive EVA
private List<SymbolInfo> FindAll(Scope scope, string Name, bool OnlyInType, bool OnlyInThisClass, Scope FromScope)
=> FindAll(scope, Name, OnlyInType, OnlyInThisClass, FromScope, SymbolTableCaseSensitive);
private List<SymbolInfo> FindAll(Scope scope, string Name, bool OnlyInType, bool OnlyInThisClass, Scope FromScope, bool caseSensitiveSearch)
{
if (OnlyInType && !(scope is ClassScope) && !(scope is SymbolTable.DotNETScope)) return null;
//if (!CaseSensitive) Name=Name.ToLower();
/*if (!scope.CaseSensitive)
Name = Name.ToLower();*/
CurrentScope = FromScope; //глобальные переменные могут привести к ошибкам при поиске и повторном вызове!
List<SymbolInfo> Result = new List<SymbolInfo>();
// Находим имена с ? в стандартных местах. Это прежде всего ?System. Потом будет ?PABCSystem.
if (Name.Equals("?System"))
{
Name = Name.Substring(1);
// Нет. Как-то найти глобальное ПИ модуля
while (scope != null && !(scope is UnitInterfaceScope))
{
if (scope is ClassMethodScope)
{
// aab 17.05.19 begin
// Поправил приоритет поиска для ?System
var classMethodScope = scope as ClassMethodScope;
if (classMethodScope.DefScope != null)
scope = classMethodScope.DefScope;
else
scope = classMethodScope.CurrentLambdaDefScope;
// aab 17.05.19 end
}
else scope = scope.TopScope;
}
if (scope != null)
{
var a = (scope as UnitInterfaceScope).TopScopeArray.Where(x => x is PascalABCCompiler.NetHelper.NetScope).ToArray();
FindAllInAreaList(Name, a, true, Result, caseSensitiveSearch);
}
if (Result.Count > 0)
return Result;
else return null;
}
Scope Area = scope;
Scope[] used_units = null;
IEnumerable<SymbolInfo> infos = null;
if (!(scope is DotNETScope))
{
Scope CurrentArea = Area;
while (CurrentArea != null)
{
if (CurrentArea is UnitPartScope) //мы очутились в модуле
{
//мы в ImplementationPart?
if (CurrentArea is UnitImplementationScope)
{
used_units = (CurrentArea as UnitImplementationScope).TopScopeArray;
infos = CurrentArea.Symbols.Find(Name, caseSensitiveSearch);
if (infos != null) //что-то нашли!
AddToSymbolInfo(infos, Result);
CurrentArea = CurrentArea.TopScope;
}
//сейча мы в InterfacePart
infos = CurrentArea.Symbols.Find(Name, caseSensitiveSearch);
if (infos != null) //что-то нашли!
AddToSymbolInfo(infos, Result);
//смотрим в модулях
FindAllInAreaList(Name, used_units, true, Result, caseSensitiveSearch);
FindAllInAreaList(Name, (CurrentArea as UnitInterfaceScope).TopScopeArray, true, Result, caseSensitiveSearch);
return Result.Count > 0 ? Result : null;
}
else
if (CurrentArea is IInterfaceScope)
{
FindAllInClass(Name, CurrentArea, OnlyInThisClass, Result, caseSensitiveSearch);
//if (Result.Count > 0) //если что-то нашли то заканчиваем
// return Result;
FindAllInAreaList(Name, (CurrentArea as IInterfaceScope).TopInterfaceScopeArray, true, Result, caseSensitiveSearch);
if (Result.Count > 0 || OnlyInType) //если что-то нашли то заканчиваем
return Result.Count > 0 ? Result : null;
}
else
if (CurrentArea is ClassScope)//мы очутились в классе
{
FindAllInClass(Name, CurrentArea, OnlyInThisClass, Result, caseSensitiveSearch);//надо сделать поиск по его предкам
if (Result.Count > 0 || OnlyInType) //если что-то нашли то заканчиваем
return Result.Count > 0 ? Result : null;
//иначе ищем дальше
}
else
if (CurrentArea is WithScope)//мы очутились в With
{
infos = CurrentArea.Symbols.Find(Name, caseSensitiveSearch);
if (infos != null) //что-то нашли!
AddToSymbolInfo(infos, Result);
if (Result.Count > 0) //если что-то нашли то заканчиваем
return Result;
Scope[] wscopes = (CurrentArea as WithScope).WithScopes;
if (wscopes != null)
foreach (Scope wsc in wscopes)
{
FindAllInClass(Name, wsc, OnlyInThisClass, Result, caseSensitiveSearch);//надо сделать поиск по его предкам
if (Result.Count > 0) //если что-то нашли то заканчиваем
return Result;
}
}
else
{
infos = CurrentArea.Symbols.Find(Name, caseSensitiveSearch);
if (infos != null) //что-то нашли!
{
AddToSymbolInfo(infos, Result);
return Result.Count > 0 ? Result : null;
}
if (CurrentArea is ClassMethodScope)//мы очутились в методе класса
{
// aab 26.04.19 begin
// Сначала ищем в скоупе где была объявлена лямбда
var currentLambdaDefScope = (CurrentArea as ClassMethodScope).CurrentLambdaDefScope;
if (currentLambdaDefScope != null)
{
var defScopeRes = FindAll(currentLambdaDefScope, Name, OnlyInType, OnlyInThisClass, currentLambdaDefScope, caseSensitiveSearch);
if (defScopeRes != null && defScopeRes.Count > 0)
{
return defScopeRes;
}
}
// aab 26.04.19 end
FindAllInClass(Name, (CurrentArea as ClassMethodScope).TopScope, OnlyInThisClass, Result, caseSensitiveSearch);//надо сделать поиск по его классу
if (Result.Count > 0) //если что-то нашли то заканчиваем
return Result;
var defScope = (CurrentArea as ClassMethodScope).DefScope;
if (defScope != null)
{
CurrentArea = defScope;
continue;
}
}
}
CurrentArea = CurrentArea.TopScope;//Пошли вверх
}
}
//если нет такого ищем в областях .NET
//ssyy
Scope NextUnitArea = null;
//\ssyy
Scope an;
infos = Area.Symbols.Find(Name, caseSensitiveSearch);
while (Area != null)
{
an = Area;
if (an is DotNETScope)
{
if (infos == null)
AddToSymbolInfo(Result, (DotNETScope)an, Name);
else
FindAllInClass(Name, Area, false, Result, caseSensitiveSearch);
}
if (Result.Count > 0)
return Result;
if (an is UnitPartScope)
{
if (an is UnitImplementationScope)
{
FindAllInAreaList(Name, (an as UnitImplementationScope).TopScopeArray, true, Result, caseSensitiveSearch);
an = an.TopScope;
}
FindAllInAreaList(Name, (an as UnitInterfaceScope).TopScopeArray, false, Result, caseSensitiveSearch);
if (Result.Count > 0)
return Result;
}
if (an is WithScope)//мы очутились в Width
{
FindAllInAreaList(Name, (an as WithScope).WithScopes, true, false, Result, caseSensitiveSearch);
if (Result.Count > 0) //если что-то нашли то заканчиваем
return Result;
}
if (an is ClassScope)
{
Scope unit_area = an.TopScope;
InterfaceScope IntScope = an as InterfaceScope;
while (((ClassScope)an).BaseClassScope != null)
{
an = ((ClassScope)an).BaseClassScope;
if (an is DotNETScope)
{
AddToSymbolInfo(Result, (DotNETScope)an, Name);
if (Result.Count > 0) // || OnlyInType)
return Result;
break;
}
}
//В предках ничего не нашли, ищем по интерфейсам...
if (IntScope != null)
{
FindAllInAreaList(Name, IntScope.TopInterfaceScopeArray, false, Result, caseSensitiveSearch);
if (Result.Count > 0) //если что-то нашли то заканчиваем
return Result;
}
if (OnlyInType)
return Result.Count > 0 ? Result : null;
//ssyy
if (NextUnitArea != null)
{
Area = NextUnitArea;
//NextUnitArea = null;
continue;
}
else
//\ssyy
an = unit_area;
}
if (Result.Count > 0)
return Result;
if (an is ClassMethodScope)
{
//ssyy
NextUnitArea = (an as ClassMethodScope).DefScope;
//\ssyy
Area = an.TopScope;
}
else
Area = Area.TopScope;
//Area = Area.TopScope;
}
return null; //если такого нет то поиск окончен
}
public int GetNewScopeNum()
{
return ++ScopeIndex;
}
}
public class TreeConverterSymbolTable:DSSymbolTable
{
public TreeConverterSymbolTable():base(SymbolTableConstants.HashTable_StartSize){}
}
public class SymbolTableController
{
public static TreeConverterSymbolTable CurrentSymbolTable = new TreeConverterSymbolTable();
}
}