Compare commits

...

1 commit

Author SHA1 Message Date
Alexander Zakharenko 88c129a3e5 Implement constructors 2018-05-26 23:46:30 +03:00
5 changed files with 119 additions and 2 deletions

View file

@ -45,8 +45,8 @@ namespace PascalABCCompiler.SyntaxTreeConverters
// Patterns
PatternsDesugaringVisitor.New.ProcessNode(root);
// Auto classes
AutoClassDesugaringVisitor.New.ProcessNode(root);
// Всё, связанное с yield
MarkMethodHasYieldAndCheckSomeErrorsVisitor.New.ProcessNode(root);

View 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;
}
}
}

View file

@ -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" />

View file

@ -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)

View file

@ -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>