// Copyright (c) Ivan Bondarev, Stanislav Mihalkovich (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 _scopesCapturedVarsNodesDictionary; private Stack _currentLambdaScopeNodeStack = new Stack(); private readonly Dictionary> _identsReferences; private CapturedVariablesTreeNode _rootNode; private CapturedVariablesTreeNodeClassScope _classScope; private CapturedVariablesTreeNodeProcedureScope _procedureScope; private List _pendingCapturedSymbols = new List(); public class CapturedVariablesInfo { public CapturedVariablesTreeNode RootNode { get; set; } public Dictionary> IdentsReferences { get; set; } public Dictionary 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(); _identsReferences = new Dictionary>(); } public override void visit(semantic_check_sugared_statement_node sn) { // Не обходить проверочные узлы в визиторе строительства дерева - SSM 1.05.17 } public override void visit(var_def_statement varDefStmt) { _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)); } if (varDefStmt.inital_value != null) { ProcessNode(varDefStmt.inital_value); } } public override void visit(statement_list stmtList) { 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); } } } public override void visit(exception_handler eh) { //_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); //_currentTreeNode.VariablesDefinedInScope.Add(new CapturedVariablesTreeNode.CapturedSymbolInfo(eh, si)); //_pendingCapturedSymbols.Add(csi); ProcessNode(eh.statements); //_pendingCapturedSymbols.Remove(csi); } public override void visit(ident id) { var idName = id.name.ToLower(); SymbolInfo si = _visitor.context.find_first(idName); 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 #167 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 || 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 || si.sym_info.semantic_node_type == semantic_node_type.class_field ; //trjuk, chtoby ne perelopachivat ves kod. zamenjaem ident na self.ident // Использую этот трюк для нестатических полей предков - они не захватываются из-за плохого алгоритма захвата if ((si.sym_info.semantic_node_type == semantic_node_type.class_field && !(si.sym_info as class_field).IsStatic || si.sym_info.semantic_node_type == semantic_node_type.common_method_node && !(si.sym_info as common_method_node).IsStatic || si.sym_info.semantic_node_type == semantic_node_type.common_event || si.sym_info.semantic_node_type == semantic_node_type.common_property_node) && InLambdaContext) { dot_node dn = new dot_node(new ident("self", id.source_context), new ident(id.name, id.source_context), id.source_context); bool ok = true; try { id.Parent.ReplaceDescendantUnsafe(id, dn); } catch { ok = false; } if (ok) { if (id.Parent is var_def_statement) ProcessNode(id); // Грубая правка, закрывающая ошибку #1390 else ProcessNode(id.Parent); // Грубо, поскольку id.Parent уже начал обходиться - а здесь рекурсия // Это рубится на коде var s := c; где s - локальная в лямбде, а c - захваченное поле класса. В результате s создаётся дважды. return; } } 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 { var field = prScope.VariablesDefinedInScope.Find(var => var.SymbolInfo == si); if (field == null) { 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(name, semClassField, pn)); } } } var idRef = (selfWordInClass ? _classScope : scope) .VariablesDefinedInScope .Find(var => var.SymbolInfo == si); if (idRef == null) //TODO: Осторожнее переделать { { return; } } if (_currentTreeNode.CorrespondingSyntaxTreeNode != null) { 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()); } _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(); 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(); 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 }; } } }