pascalabcnet/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs

903 lines
44 KiB
C#
Raw Permalink Normal View History

// 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;
using PascalABCCompiler.SystemLibrary;
using PascalABCCompiler.SemanticTree;
using PascalABCCompiler.SyntaxTree;
using PascalABCCompiler.TreeConverter;
using PascalABCCompiler.TreeRealization;
namespace TreeConverter.LambdaExpressions.Closure
{
internal class CapturedVariablesTreeBuilder : WalkingVisitorNew
{
private readonly syntax_tree_visitor _visitor;
private CapturedVariablesTreeNode _currentTreeNode;
private readonly Dictionary<int, CapturedVariablesTreeNode> _scopesCapturedVarsNodesDictionary;
private Stack<CapturedVariablesTreeNodeLambdaScope> _currentLambdaScopeNodeStack = new Stack<CapturedVariablesTreeNodeLambdaScope>();
private readonly Dictionary<SubstitutionKey, List<ident>> _identsReferences;
private CapturedVariablesTreeNode _rootNode;
private CapturedVariablesTreeNodeClassScope _classScope;
private CapturedVariablesTreeNodeProcedureScope _procedureScope;
private List<CapturedVariablesTreeNode.CapturedSymbolInfo> _pendingCapturedSymbols = new List<CapturedVariablesTreeNode.CapturedSymbolInfo>();
public class CapturedVariablesInfo
{
public CapturedVariablesTreeNode RootNode
{
get;
set;
}
public Dictionary<SubstitutionKey, List<ident>> IdentsReferences
{
get;
set;
}
public Dictionary<int, CapturedVariablesTreeNode> CapturedVarsNodesDictionary
{
get;
set;
}
public CapturedVariablesTreeNodeProcedureScope ProcedureScope
{
get;
set;
}
}
private bool InLambdaContext
{
get
{
return _currentLambdaScopeNodeStack.Count > 0;
}
}
public CapturedVariablesTreeBuilder(syntax_tree_visitor visitor)
{
_visitor = visitor;
_scopesCapturedVarsNodesDictionary = new Dictionary<int, CapturedVariablesTreeNode>();
_identsReferences = new Dictionary<SubstitutionKey, List<ident>>();
}
public override void visit(semantic_check_sugared_statement_node sn)
{
// Не обходить проверочные узлы в визиторе строительства дерева - SSM 1.05.17
}
public override void visit(assign_var_tuple assvartup)
{
_visitor.ProcessNode(assvartup);
/*foreach (var id in assvartup.idents.idents)
{
SymbolInfo si = _visitor.context.find_first(id.name);
_currentTreeNode.VariablesDefinedInScope.Add(new CapturedVariablesTreeNode.CapturedSymbolInfo(assvartup, si));
}*/
}
public override void visit(var_def_statement varDefStmt)
{
2019-06-21 21:41:45 +03:00
if (varDefStmt.inital_value != null)
{
ProcessNode(varDefStmt.inital_value);
}
_visitor.visit(varDefStmt);
foreach (var id in varDefStmt.vars.idents)
{
SymbolInfo si = _visitor.context.find_first(id.name);
_currentTreeNode.VariablesDefinedInScope.Add(new CapturedVariablesTreeNode.CapturedSymbolInfo(varDefStmt, si));
}
}
public override void visit(statement_list stmtList)
{
if (stmtList.IsInternal) // просто обойти как продолжение объемлющего statement_list
{
foreach (var stmt in stmtList.subnodes)
{
ProcessNode(stmt);
}
return;
}
var stl = new statements_list(_visitor.get_location(stmtList),
_visitor.get_location_with_check(stmtList.left_logical_bracket),
_visitor.get_location_with_check(stmtList.right_logical_bracket));
_visitor.convertion_data_and_alghoritms.statement_list_stack_push(stl);
var newTreeNode = new CapturedVariablesTreeNodeBlockScope(_currentTreeNode, stl.Scope.ScopeNum, stmtList);
if (_rootNode == null)
{
_rootNode = newTreeNode;
}
if (_currentTreeNode != null)
{
_currentTreeNode.ChildNodes.Add(newTreeNode);
}
_currentTreeNode = newTreeNode;
_scopesCapturedVarsNodesDictionary.Add(stl.Scope.ScopeNum, _currentTreeNode);
foreach (var csi in _pendingCapturedSymbols)
_currentTreeNode.VariablesDefinedInScope.Add(csi);
_pendingCapturedSymbols.Clear();
if (stmtList.subnodes != null)
{
foreach (var stmt in stmtList.subnodes)
{
ProcessNode(stmt);
}
}
_visitor.convertion_data_and_alghoritms.statement_list_stack.pop();
_currentTreeNode = _currentTreeNode.ParentNode;
}
public override void visit(new_expr newExpr)
{
if (newExpr.params_list != null && newExpr.params_list.expressions != null)
{
for (int i = 0; i < newExpr.params_list.expressions.Count; i++)
{
expression expr = newExpr.params_list.expressions[i];
ProcessNode(expr);
}
2019-06-17 01:01:53 +03:00
ProcessNode(newExpr.array_init_expr);
}
}
/*public override void visit(exception_handler eh)
{
_visitor.visit(eh);
SymbolInfo si = _visitor.context.find_first(eh.variable.name);
_currentTreeNode.VariablesDefinedInScope.Add(new CapturedVariablesTreeNode.CapturedSymbolInfo(eh, si));
ProcessNode(eh.statements);
}*/
public override void visit(exception_handler eh)
{
2019-06-29 19:28:18 +03:00
// Отдельным визитором переменные в on присвою локальным переменным и переименую везде внутри блока
statements_list sl = new statements_list(_visitor.get_location(eh.statements));
_visitor.convertion_data_and_alghoritms.statement_list_stack_push(sl);
_visitor.context.enter_code_block_without_bind();
2019-07-24 21:31:58 +03:00
if (eh.variable != null)
_visitor.context.add_var_definition(eh.variable.name, _visitor.get_location(eh.variable), _visitor.convert_strong(eh.type_name), PascalABCCompiler.SemanticTree.polymorphic_state.ps_common, true);
//SymbolInfo si = _visitor.context.find_first(eh.variable.name);
//var csi = new CapturedVariablesTreeNode.CapturedSymbolInfo(eh, si);
2019-06-29 19:28:18 +03:00
//_currentTreeNode.VariablesDefinedInScope.Add(new CapturedVariablesTreeNode.CapturedSymbolInfo(eh, si));
//_pendingCapturedSymbols.Add(csi);
2019-06-29 19:28:18 +03:00
ProcessNode(eh.variable);
ProcessNode(eh.statements);
2019-06-29 19:28:18 +03:00
_visitor.context.leave_code_block();
_visitor.convertion_data_and_alghoritms.statement_list_stack_pop();
//_pendingCapturedSymbols.Remove(csi);
}
public override void visit(ident id)
{
var idName = id.name.ToLower();
SymbolInfo si = _visitor.context.find_first(idName);
2019-06-21 08:24:10 +03:00
//var q = si.GetHashCode();
if (si == null)
{
/*if (InLambdaContext)
{
_visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id)));
return;
}*/
return;
}
if (si.sym_info.semantic_node_type == semantic_node_type.namespace_variable ||
si.sym_info.semantic_node_type == semantic_node_type.common_namespace_function_node ||
si.sym_info.semantic_node_type == semantic_node_type.namespace_constant_definition ||
si.sym_info.semantic_node_type == semantic_node_type.compiled_function_node ||
//si.sym_info.semantic_node_type == semantic_node_type.common_method_node || // SSM bug fix #1991 11.06.19 конкурирует с #891
si.sym_info.semantic_node_type == semantic_node_type.compiled_namespace_node ||
si.sym_info.semantic_node_type == semantic_node_type.compiled_variable_definition ||
si.sym_info.semantic_node_type == semantic_node_type.common_type_node ||
si.sym_info.semantic_node_type == semantic_node_type.compiled_type_node ||
si.sym_info.semantic_node_type == semantic_node_type.basic_interface_node ||
si.sym_info.semantic_node_type == semantic_node_type.common_unit_node ||
si.sym_info.semantic_node_type == semantic_node_type.common_namespace_node ||
si.sym_info.semantic_node_type == semantic_node_type.compiled_unit_node ||
si.sym_info.semantic_node_type == semantic_node_type.template_type ||
2019-10-03 12:35:58 +03:00
si.sym_info.semantic_node_type == semantic_node_type.ref_type_node ||
si.sym_info.semantic_node_type == semantic_node_type.generic_indicator ||
si.sym_info.semantic_node_type == semantic_node_type.class_constant_definition ||
si.sym_info.semantic_node_type == semantic_node_type.function_constant_definition || // SSM 03.11.18 bug fix #1449
si.sym_info.semantic_node_type == semantic_node_type.basic_function_node && (idName == "exit" || idName == "continue" || idName == "break"))
{
return;
}
var acceptableVarType = si.sym_info.semantic_node_type == semantic_node_type.local_variable ||
si.sym_info.semantic_node_type == semantic_node_type.local_block_variable ||
si.sym_info.semantic_node_type == semantic_node_type.common_parameter ||
2020-09-22 22:52:03 +03:00
si.sym_info.semantic_node_type == semantic_node_type.class_field ||
si.sym_info.semantic_node_type == semantic_node_type.basic_property_node
;
//trjuk, chtoby ne perelopachivat ves kod. zamenjaem ident na self.ident
// Использую этот трюк для нестатических полей предков - они не захватываются из-за плохого алгоритма захвата
// aab 12.06.19 begin
// Добавил такое же переименование для статичесских полей класса. Теперь захват работает
if ((si.sym_info.semantic_node_type == semantic_node_type.class_field || si.sym_info.semantic_node_type == semantic_node_type.common_method_node
2020-09-22 22:52:03 +03:00
|| si.sym_info.semantic_node_type == semantic_node_type.common_event || si.sym_info.semantic_node_type == semantic_node_type.common_property_node
|| si.sym_info.semantic_node_type == semantic_node_type.basic_property_node) && InLambdaContext)
{
2019-06-12 16:29:56 +03:00
dot_node dn = null;
2019-06-13 23:43:54 +03:00
// Поменял принцип добавления имени класса для статических полей и функций
2019-06-23 22:00:52 +03:00
Func<common_type_node, addressed_value> getClassIdent = classNode =>
2019-06-12 16:29:56 +03:00
{
2019-06-13 23:43:54 +03:00
if (classNode.name.Contains("<"))
{
var classIdent = new ident(classNode.name.Remove(classNode.name.IndexOf("<")));
2020-06-30 16:52:28 +03:00
var templateParams = new template_param_list(classNode.instance_params.Select(x => x.name)/*.Aggregate("", (acc, elem) => acc += elem)*/);
2019-06-21 08:24:10 +03:00
return new ident_with_templateparams(classIdent, templateParams);
2019-06-13 23:43:54 +03:00
}
else
{
return new ident(classNode.name);
}
};
if (si.sym_info is class_field classField && classField.IsStatic)
{
dn = new dot_node(getClassIdent(classField.cont_type),
new ident(id.name, id.source_context), id.source_context);
}
else if (si.sym_info is common_method_node commonMethodNode && commonMethodNode.IsStatic)
{
dn = new dot_node(getClassIdent(commonMethodNode.cont_type),
new ident(id.name, id.source_context), id.source_context);
2019-06-12 16:29:56 +03:00
}
2020-11-15 14:04:43 +03:00
else if (si.sym_info is common_event commonEvent && commonEvent.is_static)
{
dn = new dot_node(getClassIdent(commonEvent.cont_type),
new ident(id.name, id.source_context), id.source_context);
}
2019-06-12 16:29:56 +03:00
else
{
dn = new dot_node(new ident("self", id.source_context), new ident(id.name, id.source_context), id.source_context);
}
// aab 12.06.19 end
bool ok = true;
try
{
id.Parent.ReplaceDescendantUnsafe(id, dn);
}
catch
{
ok = false;
}
if (ok)
{
2019-06-26 16:39:47 +03:00
ProcessNode(dn); // SSM 26.06.19 #1893
/*if (id.Parent is var_def_statement)
2019-06-19 18:53:05 +03:00
ProcessNode(dn); // Грубая правка, закрывающая ошибку #1390 // SSM 19.06.19 заменил id на dn
2019-06-26 16:39:47 +03:00
else ProcessNode(dn); // Грубо, поскольку id.Parent уже начал обходиться - а здесь рекурсия // Это рубится на коде var s := c; где s - локальная в лямбде, а c - захваченное поле класса. В результате s создаётся дважды.*/
return;
}
}
if (si.sym_info.semantic_node_type == semantic_node_type.common_method_node && (si.sym_info as common_method_node).IsStatic)
{
// надо дописывать к идентификатору имя типа. Подниматься по синтаксическому дереву конечно долго ))
syntax_tree_node sn = id;
ident cname = null;
while (!(sn is procedure_definition) && sn != null) // Это если метод класса определен вне интерфейса класса
sn = sn.Parent;
if (sn != null)
{
var pd = sn as procedure_definition;
var ph = pd.proc_header;
if (ph.name.class_name != null)
{
cname = ph.name.class_name;
addressed_value id1 = null;
if (cname is template_type_name ttn)
{
var tpl = new template_param_list(ttn.template_args.idents.Select(l => SyntaxTreeBuilder.BuildSimpleType(l.name)).ToList(), ttn.template_args.source_context);
id1 = new ident_with_templateparams(new ident(ttn.name, ttn.source_context), tpl,ttn.source_context);
}
else id1 = new ident(cname.name, cname.source_context);
dot_node dn = new dot_node(id1, new ident(id.name, id.source_context), id.source_context);
id.Parent.ReplaceDescendantUnsafe(id, dn);
2019-07-02 23:04:50 +03:00
ProcessNode(dn);
return;
}
}
while (!(sn is class_definition) && sn != null)
sn = sn.Parent;
if (sn != null)
{
var cd = sn as class_definition;
cname = (cd.Parent as type_declaration).type_name;
dot_node dn = new dot_node(new ident(cname.name, cname.source_context), new ident(id.name, id.source_context), id.source_context);
id.Parent.ReplaceDescendantUnsafe(id, dn);
2019-06-23 22:00:52 +03:00
ProcessNode(dn);
}
return;
}
2020-09-22 22:52:03 +03:00
if (!acceptableVarType && InLambdaContext)
{
_visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id)));
return;
}
/*if (si.sym_info.semantic_node_type == semantic_node_type.class_field && InLambdaContext)
{
var semClassField = (class_field)si.sym_info;
if (semClassField.polymorphic_state != polymorphic_state.ps_common)
{
_visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id)));
return;
}
}*/
if (si.scope == null)
{
return;
}
var scopeIndex = si.scope.ScopeNum;
var selfWordInClass = false;
CapturedVariablesTreeNode scope;
if (_scopesCapturedVarsNodesDictionary.TryGetValue(scopeIndex, out scope))
{
var prScope = scope as CapturedVariablesTreeNodeProcedureScope;
if (prScope != null && acceptableVarType)
{
/*if (si.sym_info.semantic_node_type == semantic_node_type.local_variable)
{
if (!(idName == compiler_string_consts.self_word && si.scope is SymbolTable.ClassMethodScope && _classScope != null) && InLambdaContext)
{
_visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id)));
}
}*/
if (si.sym_info.semantic_node_type == semantic_node_type.common_parameter && prScope.FunctionNode.parameters.First(v => v.name.ToLower() == idName).parameter_type != parameter_type.value && InLambdaContext)
{
_visitor.AddError(new CannotCaptureNonValueParameters(_visitor.get_location(id)));
}
if (idName == compiler_string_consts.self_word && si.scope is SymbolTable.ClassMethodScope &&
_classScope != null)
{
var selfField = _classScope.VariablesDefinedInScope.Find(var => var.SymbolInfo == si);
if (selfField == null)
{
_classScope.VariablesDefinedInScope.Add(
new CapturedVariablesTreeNode.CapturedSymbolInfo(null, si));
}
selfWordInClass = true;
}
else
{
2019-06-21 08:24:10 +03:00
var field = prScope.VariablesDefinedInScope.Find(var => var.SymbolInfo == si);
2019-06-21 08:24:10 +03:00
if (field == null) // если не было такого
{
2019-06-21 08:24:10 +03:00
// local_block_variable common_parameter - в процедуре могут быть только эти
var found = false;
foreach (var v in prScope.VariablesDefinedInScope) // и не было с таким же именем
{
if (v.SymbolInfo.sym_info is var_definition_node vdn && vdn.name.ToLower() == id.name.ToLower()) // SSM попытка бороться с #2001 - исключаю одноимённые
{
found = true;
break;
}
}
if (!found) // то добавить
prScope.VariablesDefinedInScope.Add(new CapturedVariablesTreeNode.CapturedSymbolInfo(null, si)); // это было
}
}
}
var clScope = scope as CapturedVariablesTreeNodeClassScope;
if (clScope != null && acceptableVarType)
{
var field = clScope.VariablesDefinedInScope.Find(var => var.SymbolInfo == si);
if (field == null)
{
clScope.VariablesDefinedInScope.Add(new CapturedVariablesTreeNode.CapturedSymbolInfo(null, si));
}
if (si.access_level != access_level.al_public)
{
if (!clScope.NonPublicMembersNamesMapping.ContainsKey(idName))
{
var name = LambdaHelper.GetNameForNonPublicMember(idName);
var semClassField = (class_field) si.sym_info;
var pn = new common_property_node(name, _visitor.context._ctn, null, field_access_level.fal_public, semClassField.polymorphic_state);
pn.internal_property_type = _visitor.convert_strong(id).type;
clScope.NonPublicMembersNamesMapping.Add(idName, new Tuple<string, class_field, semantic_node>(name, semClassField, pn));
}
}
}
2019-06-21 08:24:10 +03:00
var sc = selfWordInClass ? _classScope : scope;
var idRef = sc.VariablesDefinedInScope.Find(var => var.SymbolInfo == si);
if (idRef == null) //TODO: Осторожнее переделать
{
{
2019-06-21 09:36:54 +03:00
var index = -1;
2019-06-21 08:24:10 +03:00
for (var i=0; i < sc.VariablesDefinedInScope.Count; i++)
{
if (sc.VariablesDefinedInScope[i].SymbolInfo.sym_info is var_definition_node vdn && vdn.name.ToLower() == id.name.ToLower()) // SSM #2001 и подобные - исключаю одноимённые
{
index = i;
2019-06-21 09:36:54 +03:00
si = sc.VariablesDefinedInScope[i].SymbolInfo;
2019-06-21 08:24:10 +03:00
break;
}
}
if (index == -1) // то добавить
{
sc.VariablesDefinedInScope.Add(new CapturedVariablesTreeNode.CapturedSymbolInfo(null, si));
index = sc.VariablesDefinedInScope.Count - 1;
}
2019-06-21 09:36:54 +03:00
idRef = sc.VariablesDefinedInScope[index];
if (!(idRef.SymbolInfo.sym_info is IVAriableDefinitionNode))
return; // SSM 21/06/19 - так было
}
}
if (_currentTreeNode.CorrespondingSyntaxTreeNode != null)
{
2019-06-21 09:36:54 +03:00
if (!(idRef.SymbolInfo.sym_info is IVAriableDefinitionNode)) // SSM 21/06/19
return;
var varName = ((IVAriableDefinitionNode)idRef.SymbolInfo.sym_info).name; //TODO: случай параметров и полей класса!!!!!!!!!!!!!!!!!!
var substKey = new SubstitutionKey(varName, idRef.SyntaxTreeNodeWithVarDeclaration, _currentTreeNode.CorrespondingSyntaxTreeNode);
if (!_identsReferences.ContainsKey(substKey))
{
_identsReferences.Add(substKey, new List<ident>());
}
_identsReferences[substKey].Add(id);
}
if (InLambdaContext && scope is CapturedVariablesTreeNodeLambdaScope &&
scopeIndex < _currentLambdaScopeNodeStack.Peek().ScopeIndex) //TODO: Захват параметров лямбды в другой лямбде
{
_visitor.AddError(new ThisTypeOfVariablesCannotBeCaptured(_visitor.get_location(id)));
return;
}
if (!InLambdaContext ||
scopeIndex >= _currentLambdaScopeNodeStack.Peek().ScopeIndex)
{
return;
}
var stackAsList = _currentLambdaScopeNodeStack.ToList();
stackAsList.RemoveAt(0);
if (!_currentLambdaScopeNodeStack.Peek().CapturedVarsSymbolInfo.Contains(si))
{
_currentLambdaScopeNodeStack.Peek().CapturedVarsSymbolInfo.Add(si);
foreach (var capturedVariablesTreeNodeLambdaScope in stackAsList)
{
if (!capturedVariablesTreeNodeLambdaScope.CapturedVarsSymbolInfo.Contains(si))
{
capturedVariablesTreeNodeLambdaScope.CapturedVarsSymbolInfo.Add(si);
}
}
}
if (!idRef.ReferencingLambdas.Contains(_currentLambdaScopeNodeStack.Peek()))
{
idRef.ReferencingLambdas.Add(_currentLambdaScopeNodeStack.Peek());
foreach (var capturedVariablesTreeNodeLambdaScope in stackAsList)
{
if (!idRef.ReferencingLambdas.Contains(capturedVariablesTreeNodeLambdaScope))
{
idRef.ReferencingLambdas.Add(capturedVariablesTreeNodeLambdaScope);
}
}
}
}
}
public override void visit(assign _assign)
{
var loc = _visitor.get_location(_assign);
_visitor.internal_is_assign = true;
var to = _visitor.convert_address_strong(_assign.to);
_visitor.internal_is_assign = false;
if (to == null)
_visitor.AddError(_visitor.get_location(_assign.to), "CAN_NOT_ASSIGN_TO_LEFT_PART");
bool flag;
var node_type = general_node_type.constant_definition;
if (convertion_data_and_alghoritms.check_for_constant_or_readonly(to, out flag, out node_type))
{
if (flag)
_visitor.AddError(to.location, "CAN_NOT_ASSIGN_TO_CONSTANT_OBJECT");
else
_visitor.AddError(new CanNotAssignToReadOnlyElement(to.location, node_type));
}
if (to is class_field_reference)
{
if ((to as class_field_reference).obj.type.type_special_kind == type_special_kind.record &&
(to as class_field_reference).obj is base_function_call)
{
//исключим ситуацию обращения к массиву
if (!(((to as class_field_reference).obj is common_method_call) &&
((to as class_field_reference).obj as common_method_call).obj.type.type_special_kind == type_special_kind.array_wrapper))
_visitor.AddError(loc, "LEFT_SIDE_CANNOT_BE_ASSIGNED_TO");
}
}
else if (_visitor.context.is_in_cycle() && !SemanticRules.AllowChangeLoopVariable && to.semantic_node_type == semantic_node_type.namespace_variable_reference)
{
if (_visitor.context.is_loop_variable((to as namespace_variable_reference).var))
_visitor.AddError(to.location, "CANNOT_ASSIGN_TO_LOOP_VARIABLE");
}
else if (_visitor.context.is_in_cycle() && !SemanticRules.AllowChangeLoopVariable && to.semantic_node_type == semantic_node_type.local_variable_reference)
{
if (_visitor.context.is_loop_variable((to as local_variable_reference).var))
_visitor.AddError(to.location, "CANNOT_ASSIGN_TO_LOOP_VARIABLE");
}
else if (_visitor.context.is_in_cycle() && !SemanticRules.AllowChangeLoopVariable && to.semantic_node_type == semantic_node_type.local_block_variable_reference)
{
if (_visitor.context.is_loop_variable((to as local_block_variable_reference).var))
_visitor.AddError(to.location, "CANNOT_ASSIGN_TO_LOOP_VARIABLE");
}
else if (to is simple_array_indexing)
if ((to as simple_array_indexing).simple_arr_expr is class_field_reference && ((to as simple_array_indexing).simple_arr_expr as class_field_reference).obj != null &&
((to as simple_array_indexing).simple_arr_expr as class_field_reference).obj is constant_node)
_visitor.AddError(loc, "LEFT_SIDE_CANNOT_BE_ASSIGNED_TO");
ProcessNode(_assign.to);
ProcessNode(_assign.from);
}
public override void visit(dot_node dn)
{
ProcessNode(dn.left);
if (!(dn.right is ident))
{
ProcessNode(dn.right);
}
}
public override void visit(unnamed_type_object uto) // SSM 26/08/15 - Роман подсказал
{
ProcessNode(uto.ne_list);
}
public override void visit(foreach_stmt _foreach_stmt)
{
var loopIdentName = _foreach_stmt.identifier.name.ToLower();
definition_node dn = null;
var_definition_node vdn = null;
var sl2 = new statements_list(_visitor.get_location(_foreach_stmt));
_visitor.convertion_data_and_alghoritms.statement_list_stack_push(sl2);
var newTreeNode = new CapturedVariablesTreeNodeForEachScope(_currentTreeNode, sl2.Scope.ScopeNum, _foreach_stmt);
if (_currentTreeNode != null)
{
_currentTreeNode.ChildNodes.Add(newTreeNode);
}
_currentTreeNode = newTreeNode;
_scopesCapturedVarsNodesDictionary.Add(sl2.Scope.ScopeNum, _currentTreeNode);
var inWhat = _visitor.convert_strong(_foreach_stmt.in_what);
var tmp = inWhat;
if (inWhat is typed_expression)
inWhat = _visitor.convert_typed_expression_to_function_call(inWhat as typed_expression);
type_node elemType = null;
if (inWhat.type == null)
inWhat = tmp;
bool bb; // здесь bb не нужно. Оно нужно в foreach
_visitor.FindIEnumerableElementType(/*_foreach_stmt, */inWhat.type, ref elemType, out bb);
if (_foreach_stmt.type_name == null)
{
var loc1 = _visitor.get_location(_foreach_stmt.identifier);
dn = _visitor.context.check_name_node_type(loopIdentName, loc1, general_node_type.variable_node);
vdn = (var_definition_node)dn;
}
else
{
vdn = _visitor.context.add_var_definition(loopIdentName, _visitor.get_location(_foreach_stmt.identifier));
type_node tn;
if (_foreach_stmt.type_name is no_type_foreach)
{
tn = elemType;
}
else
{
tn = _visitor.convert_strong(_foreach_stmt.type_name);
_visitor.check_for_type_allowed(tn, _visitor.get_location(_foreach_stmt.type_name));
}
_visitor.context.close_var_definition_list(tn, null);
_currentTreeNode.VariablesDefinedInScope.Add(new CapturedVariablesTreeNode.CapturedSymbolInfo(_foreach_stmt, _visitor.context.find_first(loopIdentName)));
}
newTreeNode.SymbolInfoLoopVar = _visitor.context.find_first(loopIdentName);
if (!(vdn.type is compiled_generic_instance_type_node))
_visitor.convertion_data_and_alghoritms.check_convert_type_with_inheritance(vdn.type, elemType, _visitor.get_location(_foreach_stmt.identifier));
var fn = new foreach_node(vdn, inWhat, null, _visitor.get_location(_foreach_stmt));
_visitor.context.cycle_stack.push(fn);
_visitor.context.loop_var_stack.Push(vdn);
ProcessNode(_foreach_stmt.in_what);
if (!(_foreach_stmt.stmt is statement_list))
{
var stmtList = new statement_list(_foreach_stmt.stmt, _foreach_stmt.stmt.source_context);
_foreach_stmt.stmt = stmtList;
}
ProcessNode(_foreach_stmt.stmt);
_visitor.context.loop_var_stack.Pop();
_visitor.convertion_data_and_alghoritms.statement_list_stack.pop();
_visitor.context.cycle_stack.pop();
_currentTreeNode = _currentTreeNode.ParentNode;
}
public override void visit(PascalABCCompiler.SyntaxTree.for_node _for_node)
{
var loc1 = _visitor.get_location(_for_node.loop_variable);
var loopIdentName = _for_node.loop_variable.name.ToLower();
var nodesToProcess = new List<syntax_tree_node>();
var_definition_node vdn;
var initv = _visitor.convert_strong(_for_node.initial_value);
var tmp = initv;
if (initv is typed_expression)
{
initv = _visitor.convert_typed_expression_to_function_call(initv as typed_expression);
}
if (initv.type == null)
{
initv = tmp;
}
var headStmts = new statements_list(loc1);
_visitor.convertion_data_and_alghoritms.statement_list_stack_push(headStmts);
var newTreeNode = new CapturedVariablesTreeNodeForScope(_currentTreeNode, headStmts.Scope.ScopeNum, _for_node);
if (_currentTreeNode != null)
{
_currentTreeNode.ChildNodes.Add(newTreeNode);
}
_currentTreeNode = newTreeNode;
_scopesCapturedVarsNodesDictionary.Add(headStmts.Scope.ScopeNum, _currentTreeNode);
if (_for_node.type_name == null && !_for_node.create_loop_variable)
{
var dn = _visitor.context.check_name_node_type(loopIdentName, loc1, general_node_type.variable_node);
vdn = (var_definition_node)dn;
nodesToProcess.Add(_for_node.loop_variable);
}
else
{
var tn = _for_node.type_name != null ? _visitor.convert_strong(_for_node.type_name) : initv.type;
vdn = _visitor.context.add_var_definition(loopIdentName,
_visitor.get_location(_for_node.loop_variable), tn,
polymorphic_state.ps_common);
_currentTreeNode.VariablesDefinedInScope.Add(new CapturedVariablesTreeNode.CapturedSymbolInfo(_for_node, _visitor.context.find_first(loopIdentName)));
}
newTreeNode.SymbolInfoLoopVar = _visitor.context.find_first(loopIdentName);
var fn = new PascalABCCompiler.TreeRealization.for_node(null, null, null, null, null, _visitor.get_location(_for_node));
if (vdn.type == SystemLibrary.bool_type)
{
fn.bool_cycle = true;
}
_visitor.context.cycle_stack.push(fn);
_visitor.context.loop_var_stack.Push(vdn);
nodesToProcess.Add(_for_node.initial_value);
nodesToProcess.Add(_for_node.finish_value);
nodesToProcess.Add(_for_node.increment_value);
foreach (var n in nodesToProcess)
{
ProcessNode(n);
}
if (!(_for_node.statements is statement_list))
{
var stmtList = new statement_list(_for_node.statements, _for_node.statements.source_context);
_for_node.statements = stmtList;
}
ProcessNode(_for_node.statements);
_visitor.context.cycle_stack.pop();
_visitor.context.loop_var_stack.Pop();
_visitor.convertion_data_and_alghoritms.statement_list_stack.pop();
_currentTreeNode = _currentTreeNode.ParentNode;
}
public override void visit(function_lambda_definition lambdaDefinition)
{
if (lambdaDefinition.formal_parameters != null && lambdaDefinition.formal_parameters.params_list != null && lambdaDefinition.formal_parameters.params_list.Count != 0)
{
var varDefsList = new List<statement>();
for (var i = 0; i < lambdaDefinition.formal_parameters.params_list.Count; i++)
{
var varType = lambdaDefinition.formal_parameters.params_list[i].vars_type is lambda_inferred_type ?
LambdaHelper.ConvertSemanticTypeToSyntaxType((type_node)((lambda_inferred_type)lambdaDefinition.formal_parameters.params_list[i].vars_type).real_type) :
//new semantic_type_node(((lambda_inferred_type)lambdaDefinition.formal_parameters.params_list[i].vars_type).real_type): // SSM 29/12/18 поменял - пробую - не получилось
lambdaDefinition.formal_parameters.params_list[i].vars_type;
for (var j = 0; j < lambdaDefinition.formal_parameters.params_list[i].idents.idents.Count; j++)
{
var varName = "<>" + lambdaDefinition.formal_parameters.params_list[i].idents.idents[j].name;
SourceContext sc = lambdaDefinition.formal_parameters.params_list[i].idents.idents[j].source_context;
var vds = new var_def_statement(new ident(lambdaDefinition.formal_parameters.params_list[i].idents.idents[j].name, sc), varType, sc);
vds.inital_value = new ident(varName, sc);
lambdaDefinition.formal_parameters.params_list[i].idents.idents[j].name = varName;
varDefsList.Add(new var_statement(vds, sc));
}
}
((statement_list)lambdaDefinition.proc_body).subnodes.InsertRange(0, varDefsList);
}
var procDecl = LambdaHelper.ConvertLambdaNodeToProcDefNode(lambdaDefinition);
_visitor.body_exists = true;
_visitor.hard_node_test_and_visit(procDecl.proc_header);
var newTreeNode = new CapturedVariablesTreeNodeLambdaScope(_currentTreeNode,
lambdaDefinition,
_visitor.context.func_stack.top().scope.ScopeNum, lambdaDefinition);
_currentTreeNode.LambdasDefinedInScope.Add(newTreeNode);
_currentLambdaScopeNodeStack.Push(newTreeNode);
if (_currentTreeNode != null)
{
_currentTreeNode.ChildNodes.Add(newTreeNode);
}
_currentTreeNode = newTreeNode;
_scopesCapturedVarsNodesDictionary.Add(_currentTreeNode.ScopeIndex, _currentTreeNode);
VisitProcParameters(procDecl.proc_header.parameters);
ProcessNode(procDecl.proc_body);
_visitor.context.leave_block();
_visitor.context.remove_lambda_function(procDecl.proc_header.name.meth_name.name, false);
_currentTreeNode = _currentTreeNode.ParentNode;
_currentLambdaScopeNodeStack.Pop();
LambdaHelper.RemoveLambdaInfoFromCompilationContext(_visitor.context, lambdaDefinition);
}
public override void visit(name_assign_expr nae) // Не надо захватывать явные имена полей в безымянных классах
{
// ProcessNode(nae.name); - пропустить!
ProcessNode(nae.expr);
}
public override void visit(with_statement _with_statement)
{
_visitor.AddError(_visitor.get_location(_with_statement), "WITH_AND_LAMBDAS_NOT_ALLOWED");
}
public override void visit(PascalABCCompiler.SyntaxTree.goto_statement _goto_statement)
{
if (_goto_statement.source_context != null) // видимо, это сделано для того чтобы сахарные конструкции всё же можно было использовать с лямбдами. То есть, это какое-то искусственное ограничение
{
//_visitor.AddError(_visitor.get_location(_goto_statement), "GOTO_AND_LAMBDAS_NOT_ALLOWED");
}
else
base.visit(_goto_statement);
}
private void VisitProcParameters(formal_parameters procParametres)
{
if (procParametres == null ||
procParametres.params_list == null)
{
return;
}
foreach (var tp in procParametres.params_list)
{
foreach (var id in tp.idents.idents)
{
SymbolInfo si = _visitor.context.find_first(id.name);
_currentTreeNode.VariablesDefinedInScope.Add(new CapturedVariablesTreeNode.CapturedSymbolInfo(tp, si));
}
}
}
private void CreateNodesForUpperScopesIfExist()
{
if (_visitor.context._ctn != null)
{
_rootNode = new CapturedVariablesTreeNodeClassScope(null, _visitor.context._ctn.Scope.ScopeNum, null, _visitor.context._ctn.name);
_currentTreeNode = _rootNode;
_scopesCapturedVarsNodesDictionary.Add(_visitor.context._ctn.Scope.ScopeNum, _currentTreeNode);
_classScope = (CapturedVariablesTreeNodeClassScope) _rootNode;
}
if (_visitor.context.func_stack.top() != null)
{
var newTreeNode = new CapturedVariablesTreeNodeProcedureScope(_currentTreeNode, _visitor.context.func_stack.top(), _visitor.context.func_stack.top().scope.ScopeNum, null);
if (_rootNode == null)
{
_rootNode = newTreeNode;
}
if (_currentTreeNode != null)
{
_currentTreeNode.ChildNodes.Add(newTreeNode);
}
_currentTreeNode = newTreeNode;
_scopesCapturedVarsNodesDictionary.Add(_visitor.context.func_stack.top().scope.ScopeNum, _currentTreeNode);
_procedureScope = (CapturedVariablesTreeNodeProcedureScope) _currentTreeNode;
}
}
private CapturedVariablesTreeNode BuildTreeForStatementList(statement_list statementList)
{
CreateNodesForUpperScopesIfExist();
ProcessNode(statementList);
return _rootNode;
}
public CapturedVariablesInfo BuildTree(statement_list statementList)
{
return new CapturedVariablesInfo
{
RootNode = BuildTreeForStatementList(statementList),
IdentsReferences = _identsReferences,
CapturedVarsNodesDictionary = _scopesCapturedVarsNodesDictionary,
ProcedureScope = _procedureScope
};
}
}
}