Compare commits
1 commit
master
...
features/r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88c129a3e5 |
|
|
@ -45,8 +45,8 @@ namespace PascalABCCompiler.SyntaxTreeConverters
|
|||
// Patterns
|
||||
PatternsDesugaringVisitor.New.ProcessNode(root);
|
||||
|
||||
|
||||
|
||||
// Auto classes
|
||||
AutoClassDesugaringVisitor.New.ProcessNode(root);
|
||||
|
||||
// Всё, связанное с yield
|
||||
MarkMethodHasYieldAndCheckSomeErrorsVisitor.New.ProcessNode(root);
|
||||
|
|
|
|||
107
SyntaxVisitors/SugarVisitors/AutoClassDesugaringVisitor.cs
Normal file
107
SyntaxVisitors/SugarVisitors/AutoClassDesugaringVisitor.cs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
using PascalABCCompiler.SyntaxTree;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace SyntaxVisitors.SugarVisitors
|
||||
{
|
||||
public class AutoClassDesugaringVisitor : BaseChangeVisitor
|
||||
{
|
||||
private Dictionary<string, class_definition> autoClassDefinitions = new Dictionary<string, class_definition>();
|
||||
|
||||
public static AutoClassDesugaringVisitor New => new AutoClassDesugaringVisitor();
|
||||
|
||||
public override void visit(type_declaration typeDeclaration)
|
||||
{
|
||||
var isAutoClass = typeDeclaration.type_def is class_definition classDefinition && IsAutoClass(classDefinition);
|
||||
if (!isAutoClass)
|
||||
return;
|
||||
|
||||
// Добавляем автокласс в словарь
|
||||
classDefinition = typeDeclaration.type_def as class_definition;
|
||||
autoClassDefinitions[typeDeclaration.type_name.name] = classDefinition;
|
||||
|
||||
CheckAutoClassInheritance(classDefinition);
|
||||
CheckAutoClassBody(classDefinition);
|
||||
|
||||
var fieldNames = new List<ident>();
|
||||
var fieldTypes = new List<type_definition>();
|
||||
CollectAutoClassRegularFields(classDefinition, ref fieldNames, ref fieldTypes);
|
||||
var constructor = SyntaxTreeBuilder.BuildSimpleConstructorSection(fieldNames, fieldNames.Select(x => new ident('_' + x.name)).ToList(), fieldTypes);
|
||||
classDefinition.body.Add(constructor);
|
||||
}
|
||||
|
||||
private bool IsAutoClass(class_definition classDefinition) => (classDefinition.attribute & class_attribute.Auto) == class_attribute.Auto;
|
||||
|
||||
private bool AutoClassExists(string className) => className != null && autoClassDefinitions.ContainsKey(className);
|
||||
|
||||
private void CheckAutoClassInheritance(class_definition classDefinition)
|
||||
{
|
||||
if (classDefinition?.class_parents?.Count > 1)
|
||||
throw new SyntaxVisitorError("AUTO_CLASS_CAN_ONLY_HAVE_ONE_PARENT_CLASS", classDefinition.source_context);
|
||||
|
||||
if (classDefinition?.class_parents?.Count > 0 && !AutoClassExists(GetAutoClassParentName(classDefinition)))
|
||||
throw new SyntaxVisitorError("AUTO_CLASS_CAN_BE_INHERITED_ONLY_FROM_ANOTHER_AUTO_CLASS", classDefinition.source_context);
|
||||
}
|
||||
|
||||
private void CheckAutoClassBody(class_definition classDefinition)
|
||||
{
|
||||
// Запрещаем все кроме полей
|
||||
if (classDefinition.body.class_def_blocks.Any(block => block.members.Any(member => !(member is var_def_statement))))
|
||||
throw new SyntaxVisitorError("AUTO_CLASS_CAN_ONLY_CONTAIN_FIELD_DECLARATIONS", classDefinition.source_context);
|
||||
}
|
||||
|
||||
private void CollectAutoClassRegularFields(class_definition classDefinition, ref List<ident> names, ref List<type_definition> types)
|
||||
{
|
||||
if (classDefinition?.class_parents?.Count > 0)
|
||||
{
|
||||
var hasParent = GetAutoClassParent(classDefinition, out var definition, out _);
|
||||
CollectAutoClassRegularFields(classDefinition, ref names, ref types);
|
||||
}
|
||||
|
||||
var varDefs = CollectAutoClassVarDefs(classDefinition);
|
||||
names.AddRange(varDefs.Select(x => x.vars).SelectMany(x => x.list));
|
||||
types.AddRange(varDefs.SelectMany(x => Enumerable.Repeat(x.vars_type, x.vars.Count)));
|
||||
}
|
||||
|
||||
private IEnumerable<var_def_statement> CollectAutoClassVarDefs(class_definition classDefinition) =>
|
||||
classDefinition.body.class_def_blocks.SelectMany(block => block.members.OfType<var_def_statement>());
|
||||
|
||||
private string GetAutoClassParentName(class_definition classDefinition)
|
||||
{
|
||||
GetAutoClassParent(classDefinition, out _, out string parentName);
|
||||
return parentName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получает предка класса, только если он тоже автокласс
|
||||
/// </summary>
|
||||
/// <param name="classDefinition"></param>
|
||||
/// <param name="definition"></param>
|
||||
/// <param name="parentName"></param>
|
||||
/// <returns></returns>
|
||||
private bool GetAutoClassParent(class_definition classDefinition, out class_definition definition, out string parentName)
|
||||
{
|
||||
parentName = null;
|
||||
definition = null;
|
||||
|
||||
if (classDefinition?.class_parents?.Count > 0)
|
||||
{
|
||||
parentName = classDefinition.class_parents.types
|
||||
.Where(x => autoClassDefinitions.ContainsKey(x.names[0].name))
|
||||
.Select(x => x.names[0].name)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (parentName != null)
|
||||
{
|
||||
definition = autoClassDefinitions[parentName];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -52,6 +52,7 @@
|
|||
<Compile Include="LightSymInfoVisitors\SymInfoCollect1.cs" />
|
||||
<Compile Include="LightSymInfoVisitors\SymInfoCollect1Helper.cs" />
|
||||
<Compile Include="SugarVisitors\AssignTuplesDesugarVisitor.cs" />
|
||||
<Compile Include="SugarVisitors\AutoClassDesugaringVisitor.cs" />
|
||||
<Compile Include="SugarVisitors\DoubleQuestionDesugarVisitor.cs" />
|
||||
<Compile Include="SugarVisitors\LoopDesugarVisitor.cs" />
|
||||
<Compile Include="SugarVisitors\QuestionPointDesugarVisitor.cs" />
|
||||
|
|
|
|||
|
|
@ -3592,6 +3592,9 @@ namespace PascalABCCompiler.TreeConverter
|
|||
/*if (_class_definition.class_parents!=null)
|
||||
AddError(new AutoClassMustNotHaveParents(get_location(_class_definition)));*/
|
||||
// добавление членов автоклассов. Не забыть сделать, что от автоклассов нельзя наследовать
|
||||
|
||||
// Закоментировал для реализации record-classes
|
||||
/*
|
||||
SyntaxTreeBuilder.AddMembersForAutoClass(_class_definition,ref names,ref types);
|
||||
for (var i = 0; i < types.Count; i++)
|
||||
{
|
||||
|
|
@ -3615,6 +3618,8 @@ namespace PascalABCCompiler.TreeConverter
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
//if (!SemanticRules.OrderIndependedNames)
|
||||
|
||||
|
|
|
|||
|
|
@ -102,6 +102,9 @@
|
|||
<Reference Include="System.Design" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Messaging" />
|
||||
<Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.ValueTuple.4.4.0\lib\portable-net40+sl4+win8+wp8\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Windows.Forms.DataVisualization" />
|
||||
<Reference Include="System.Xaml" />
|
||||
|
|
@ -532,6 +535,7 @@
|
|||
<EmbeddedResource Include="FormsDesignerBinding\FormsDesigner\Resources\ConfigureSidebarDialog.xfrm" />
|
||||
<EmbeddedResource Include="FormsDesignerBinding\FormsDesigner\Resources\RenameSidebarCategoryDialog.xfrm" />
|
||||
<EmbeddedResource Include="FormsDesignerBinding\FormsDesigner\Resources\WindowsFormsGeneralOptions.xfrm" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
|
|
|
|||
Loading…
Reference in a new issue