pascalabcnet/SyntaxVisitors/SugarVisitors/PropertyDesugarVisitor.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

222 lines
9.2 KiB
C#

using PascalABCCompiler.SyntaxTree;
using PascalABCCompiler.CoreUtils;
using System.Collections.Generic;
namespace SyntaxVisitors.SugarVisitors
{
public class PropertyDesugarVisitor : BaseChangeVisitor
{
private readonly GeneratedNamesManager generatedNamesManager;
private PropertyDesugarVisitor(GeneratedNamesManager generatedNamesManager)
{
this.generatedNamesManager = generatedNamesManager;
}
public static PropertyDesugarVisitor Create(GeneratedNamesManager generatedNamesManager) => new PropertyDesugarVisitor(generatedNamesManager);
public override void visit(class_members _class_members)
{
foreach (var member in _class_members.members)
{
if (member is simple_property)
{
Desugar(member as simple_property);
}
}
}
private void Desugar(simple_property _simple_property)
{
var property_parent_node = _simple_property.Parent;
while (property_parent_node != null && property_parent_node.GetType() != typeof(class_members))
{
property_parent_node = property_parent_node.Parent;
}
class_members property_class_members = property_parent_node as class_members;
while (property_parent_node != null && property_parent_node.GetType() != typeof(class_body_list))
{
property_parent_node = property_parent_node.Parent;
}
class_body_list class_body = property_parent_node as class_body_list;
while (property_parent_node != null && property_parent_node.GetType() != typeof(class_definition))
{
property_parent_node = property_parent_node.Parent;
}
class_definition class_def = property_parent_node as class_definition;
var property_type = _simple_property.property_type;
var read_accessor = _simple_property.accessors?.read_accessor;
var write_accessor = _simple_property.accessors?.write_accessor;
var new_class_members = new class_members(access_modifer.private_modifer);
if (class_def.keyword == class_keyword.Interface && _simple_property.is_auto)
{
throw new SyntaxVisitorError(
"INVALID_INTERFACE_MEMBER", _simple_property.source_context);
}
if (class_def.keyword == class_keyword.Interface &&
read_accessor != null &&
(read_accessor.pr != null || read_accessor.accessor_name != null))
{
throw new SyntaxVisitorError(
"INVALID_INTERFACE_MEMBER", read_accessor.source_context);
}
if (class_def.keyword == class_keyword.Interface &&
write_accessor != null &&
(write_accessor.pr != null || write_accessor.accessor_name != null))
{
throw new SyntaxVisitorError(
"INVALID_INTERFACE_MEMBER", write_accessor.source_context);
}
if (_simple_property.is_auto)
{
if (_simple_property.parameter_list != null)
{
throw new SyntaxVisitorError(
"INDEXED_AUTO_PROPERTY", _simple_property.source_context);
}
AutoPropertyDesugaring(_simple_property, new_class_members);
}
// pr != null => extended read accessor
if (read_accessor != null && read_accessor.pr != null)
{
ExtendedReadAccessorDesugaring(read_accessor, _simple_property, new_class_members);
}
// pr != null => extended write accessor
if (write_accessor != null && write_accessor.pr != null)
{
ExtendedWriteAccessorDesugaring(write_accessor, _simple_property, new_class_members);
}
if (new_class_members.Count > 0)
{
class_body.InsertBefore(property_class_members, new_class_members);
}
}
private void AutoPropertyDesugaring(simple_property simple_property,
class_members members)
{
var id = NewId("#PField", simple_property.source_context);
var accessors = new property_accessors();
accessors.write_accessor = new write_accessor_name(id, null, null, simple_property.source_context);
accessors.read_accessor = new read_accessor_name(id, null, null, simple_property.source_context);
simple_property.accessors = accessors;
var def_attribute = definition_attribute.None;
if (simple_property.attr == definition_attribute.Static)
{
def_attribute = definition_attribute.Static;
}
List<ident> l = new List<ident>() { id };
var var_def_statement = new var_def_statement(
new ident_list(l, simple_property.source_context),
simple_property.property_type,
simple_property.initial_value,
def_attribute,
false,
simple_property.source_context);
members.Add(var_def_statement);
}
private void ExtendedReadAccessorDesugaring(read_accessor_name read_accessor,
simple_property simple_property,
class_members members)
{
var read_accessor_procedure = read_accessor.pr as procedure_definition;
var func_header = (read_accessor_procedure.proc_header as function_header);
func_header.return_type = simple_property.property_type;
//extended indexed property
if (simple_property.parameter_list != null)
{
var func_header_params = new List<ident>();
var func_header_types = new List<type_definition>();
foreach (var param in simple_property.parameter_list.parameters)
{
foreach (var ident in param.names.idents)
{
func_header_params.Add(ident);
func_header_types.Add(param.type);
}
}
func_header.parameters =
SyntaxTreeBuilder.BuildFormalParameters(
func_header_params,
func_header_types);
}
members.Add(read_accessor_procedure);
if (simple_property.attr == definition_attribute.Static)
{
read_accessor_procedure.proc_header.class_keyword = true;
var proc_attr = new procedure_attribute(proc_attribute.attr_static);
proc_attr.source_context = read_accessor_procedure.proc_header.source_context;
read_accessor_procedure.proc_header.proc_attributes = new procedure_attributes_list(proc_attr);
}
}
private void ExtendedWriteAccessorDesugaring(write_accessor_name write_accessor,
simple_property simple_property,
class_members members)
{
var write_accessor_procedure = write_accessor.pr as procedure_definition;
//extended indexed property
if (simple_property.parameter_list != null)
{
var proc_header_params = new List<ident>();
var proc_header_types = new List<type_definition>();
foreach (var param in simple_property.parameter_list.parameters)
{
foreach (var ident in param.names.idents)
{
proc_header_params.Add(ident);
proc_header_types.Add(param.type);
}
}
proc_header_params.Add(new ident("value"));
proc_header_types.Add(simple_property.property_type);
write_accessor_procedure.proc_header.parameters =
SyntaxTreeBuilder.BuildFormalParameters(
proc_header_params,
proc_header_types);
}
else
{
write_accessor_procedure.proc_header.parameters.params_list[0].vars_type = simple_property.property_type;
}
members.Add(write_accessor_procedure);
if (simple_property.attr == definition_attribute.Static)
{
write_accessor_procedure.proc_header.class_keyword = true;
var proc_attr = new procedure_attribute(proc_attribute.attr_static);
proc_attr.source_context = write_accessor_procedure.proc_header.source_context;
write_accessor_procedure.proc_header.proc_attributes = new procedure_attributes_list(proc_attr);
}
}
//random id generator
public ident NewId(string prefix, SourceContext sc = null)
{
return new ident(generatedNamesManager.GenerateName(prefix), sc);
}
}
}