From 88c129a3e5a29398c9a3cf31c7b7911970b2e2d4 Mon Sep 17 00:00:00 2001 From: Alexander Zakharenko Date: Sat, 26 May 2018 23:46:30 +0300 Subject: [PATCH] Implement constructors --- .../StandardSyntaxConverter.cs | 4 +- .../AutoClassDesugaringVisitor.cs | 107 ++++++++++++++++++ SyntaxVisitors/SyntaxVisitors.csproj | 1 + .../TreeConversion/syntax_tree_visitor.cs | 5 + VisualPascalABCNET/VisualPascalABCNET.csproj | 4 + 5 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 SyntaxVisitors/SugarVisitors/AutoClassDesugaringVisitor.cs diff --git a/SyntaxTreeConverters/StandardSyntaxConverter.cs b/SyntaxTreeConverters/StandardSyntaxConverter.cs index f56cdf1aa..7bd9e62be 100644 --- a/SyntaxTreeConverters/StandardSyntaxConverter.cs +++ b/SyntaxTreeConverters/StandardSyntaxConverter.cs @@ -45,8 +45,8 @@ namespace PascalABCCompiler.SyntaxTreeConverters // Patterns PatternsDesugaringVisitor.New.ProcessNode(root); - - + // Auto classes + AutoClassDesugaringVisitor.New.ProcessNode(root); // Всё, связанное с yield MarkMethodHasYieldAndCheckSomeErrorsVisitor.New.ProcessNode(root); diff --git a/SyntaxVisitors/SugarVisitors/AutoClassDesugaringVisitor.cs b/SyntaxVisitors/SugarVisitors/AutoClassDesugaringVisitor.cs new file mode 100644 index 000000000..7eeeca875 --- /dev/null +++ b/SyntaxVisitors/SugarVisitors/AutoClassDesugaringVisitor.cs @@ -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 autoClassDefinitions = new Dictionary(); + + 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(); + var fieldTypes = new List(); + 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 names, ref List 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 CollectAutoClassVarDefs(class_definition classDefinition) => + classDefinition.body.class_def_blocks.SelectMany(block => block.members.OfType()); + + private string GetAutoClassParentName(class_definition classDefinition) + { + GetAutoClassParent(classDefinition, out _, out string parentName); + return parentName; + } + + /// + /// Получает предка класса, только если он тоже автокласс + /// + /// + /// + /// + /// + 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; + } + } +} diff --git a/SyntaxVisitors/SyntaxVisitors.csproj b/SyntaxVisitors/SyntaxVisitors.csproj index 8c888098a..796bc20de 100644 --- a/SyntaxVisitors/SyntaxVisitors.csproj +++ b/SyntaxVisitors/SyntaxVisitors.csproj @@ -52,6 +52,7 @@ + diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index 3b06c893b..acbee3dee 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.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) diff --git a/VisualPascalABCNET/VisualPascalABCNET.csproj b/VisualPascalABCNET/VisualPascalABCNET.csproj index 4eca7233a..cedb5e5de 100644 --- a/VisualPascalABCNET/VisualPascalABCNET.csproj +++ b/VisualPascalABCNET/VisualPascalABCNET.csproj @@ -102,6 +102,9 @@ + + ..\packages\System.ValueTuple.4.4.0\lib\portable-net40+sl4+win8+wp8\System.ValueTuple.dll + @@ -532,6 +535,7 @@ + SettingsSingleFileGenerator Settings.Designer.cs