pascalabcnet/SyntaxVisitors/YieldVisitors/ReplaceCapturedVariablesVisitor.cs
Александр Земляк 1f4b44c2c0
Исправление ошибок при перекомпиляции pcu файлов (#3398)
* Move yield string constants to StringConstants class

* Add GeneratedNamesManager class to store all generated names during unit compilation

* Make GeneratedNamesManager class non static

* Add Utils project to installer files

* Add GeneratedNamesManager usage in CapturedVariablesSubstitutionsManager

* Move GeneratedNamesManager initialization in CompilationUnit constructor

* More GeneratedNamesManager usage

* QuestionPointDesugarVisitor fix
2026-03-08 18:30:33 +03:00

200 lines
7.4 KiB
C#

// 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.Collections.Generic;
using PascalABCCompiler;
using PascalABCCompiler.SyntaxTree;
namespace SyntaxVisitors
{
public class ReplaceCapturedVariablesVisitor : BaseChangeVisitor
{
private ISet<string> CollectedLocals = new HashSet<string>();
private ISet<string> CollectedFormalParams = new HashSet<string>();
private ISet<string> CollectedClassFields = new HashSet<string>();
private ISet<string> CollectedUnitGlobals = new HashSet<string>();
// Maps :: idName -> capturedName
private IDictionary<string, string> CapturedLocalsMap = new Dictionary<string, string>();
private IDictionary<string, string> CapturedFormalParamsMap = new Dictionary<string, string>();
private bool IsInClassMethod = true;
private bool IsStaticMethod = false;
private ident ClassName;
public ReplaceCapturedVariablesVisitor(IEnumerable<string> locals,
IEnumerable<string> formalParams,
IEnumerable<string> classFields,
IEnumerable<string> classMethods,
IEnumerable<string> classProperties,
IEnumerable<string> unitGlobals,
IDictionary<string, string> localsMap,
IDictionary<string, string> formalParamsMap,
bool isInClassMethod, bool isStaticMethod, ident className)
{
CollectedLocals = new HashSet<string>(locals);
CollectedFormalParams = new HashSet<string>(formalParams);
CollectedClassFields = new HashSet<string>(classFields);
CollectedUnitGlobals = new HashSet<string>(unitGlobals);
CapturedLocalsMap = new Dictionary<string, string>(localsMap);
CapturedFormalParamsMap = new Dictionary<string, string>(formalParamsMap);
IsInClassMethod = isInClassMethod;
IsStaticMethod = isStaticMethod;
ClassName = className;
// Methods hack
CollectedClassFields.UnionWith(classMethods);
// Properties hack
CollectedClassFields.UnionWith(classProperties);
}
public override void visit(labeled_statement ls)
{
ProcessNode(ls.to_statement);
}
public override void visit(goto_statement gt)
{
// Empty
}
// frninja 12/05/16 - фикс для yield_unknown_ident
public override void visit(yield_unknown_ident unk)
{
//yield_var_def_statement_with_unknown_type x;
// Empty
}
public override void visit(ident id)
{
// Check dot node
var upper = UpperNode(1);
//if (upper is dot_node)
// return;
var idName = id.name.ToLower();
var idSourceContext = id.source_context;
// frninja 31/03/16 - фикс селфа для extensionmethod
if (idName == "self" && !CollectedFormalParams.Contains(idName))
{
var newSelf = new dot_node(new ident("self"), new ident(StringConstants.yieldSelf));
Replace(id, newSelf);
return;
}
// Detect where is id from
if (CollectedLocals.Contains(idName))
{
Replace(id, new ident(CapturedLocalsMap[idName], idSourceContext));
}
else if (CollectedFormalParams.Contains(idName))
{
Replace(id, new ident(CapturedFormalParamsMap[idName], idSourceContext));
}
else if (IsInClassMethod)
{
// In class -> check fields
//if (CollectedClassFields.Contains(idName))
{
// Good
// Name in class fields -> capture as class field
//var capturedId = new dot_node(new dot_node(new ident("self"), new ident(YieldConsts.Self)), id);
//var capturedId = new dot_node(ClassName, id.TypedClone());
//Replace(id, capturedId);
}
//else
{
// Bad
// At syntax we don't know if the className is class field or not coz of e.g. base .NET classes
// HERE WE SHOULD REPLACE TO yield_unknown_reference -> so decision is passed to semantic
// Check for globals will be processed at semantic, too
if (!id.name.StartsWith("<")) // Check for already captured
{
Replace(id, new yield_unknown_ident(id, ClassName, this.IsStaticMethod));
}
}
}
else
{
// Not in class -> check globals
if (CollectedUnitGlobals.Contains(idName))
{
// Global -> just do nothing
}
else
{
// What about static classes - search at semantic
// HERE WE SHOULD REPLACE TO yield_unknown_reference -> so decision is passed to semantic
}
}
}
/*public override void visit(procedure_call pc)
{
ProcessNode(pc.func_name);
var methCall = pc.func_name as method_call;
if ((object)methCall != null)
{
foreach (var param in methCall.parameters.expressions)
{
param.visit(this);
}
}
}*/
public override void visit(dot_node dn)
{
var rid = dn.right as ident;
if ((object)rid != null && rid.name != StringConstants.yieldSelf)
ProcessNode(dn.left);
// Most nested
// DotNode (DLeft, DRight) -> DotNode(DotNode("self", "<>__self"), DRight)
// LEFT self -> captured self (self.captured_self)
/*var id = dn.left as ident;
if ((object)id != null && (id.className == "self" || CollectedClassFields.Contains(id.className)))
{
// Some magic for blocking back-traverse from BaseChangeVisitor redoin' work
//var rid = dn.right as ident;
//if ((object)rid != null && rid.className != Consts.Self)
{
var newDotNode = new dot_node(new dot_node(new ident("self"), new ident(Consts.Self)), dn.right);
// Change right?
//var capturedRight = new dot_node(new ident(Consts.Self), dn.right);
//var newDotNode = new dot_node(dn.left, capturedRight);
Replace(dn, newDotNode);
}
// Some magic for blocking back-traverse from BaseChangeVisitor redoin' work
//var rid = dn.right as ident;
//if ((object)rid != null && rid.className != Consts.Self)
// {
// var capturedSelf = new dot_node(new ident("self"), new ident(Consts.Self));
// Replace(dn.left, capturedSelf);
// }
}
else
{
ProcessNode(dn.left);
}*/
//if (dn.right.GetType() != typeof(ident))
// ProcessNode(dn.right);
}
}
}