Implement deconstruction, simple case

This commit is contained in:
Alexander Zakharenko 2018-05-06 20:09:36 +03:00
parent ed621517f3
commit 9d3fd3e5aa
12 changed files with 728 additions and 91 deletions

View file

@ -5,6 +5,30 @@ end;
// Desugared code
var <>genVarExpr := e;
var <>genVar: Person;
if IsTest(<>genVarExpr, <>genVar) then
begin
// always the same code
var value: ?; // should be filled during semantic analysis
<>genVar.Deconstruct(value);
<ACTION>
end;
{
info we need to fill the tree:
1. Syntactic nodes of parameters' types
}
// ****************************************************************************
// Source
if e is Person(var value) then
<ACTION>
// Desugared code
var <>genVar: Person;
if IsTest(e, <>genVar) then
begin
@ -15,7 +39,19 @@ begin
<ACTION>
end;
{
info we need to fill the tree:
1. Syntactic nodes of parameters' types
}
// ****************************************************************************
// Source
var res := e is Person(var value);
// Desugared code
var <>genVar: Person;
if IsTest(e, <>genVar) then
begin
// always the same code
var value: ?; // should be filled during semantic analysis
<>genVar.Deconstruct(value);
<ACTION>
end;

View file

@ -1157,6 +1157,11 @@ namespace PascalABCCompiler.SyntaxTree
{
DefaultVisit(_pattern_deconstructor_parameter);
}
public virtual void visit(desugared_deconstruction _desugared_deconstruction)
{
DefaultVisit(_desugared_deconstruction);
}
}

View file

@ -1845,6 +1845,14 @@ namespace PascalABCCompiler.SyntaxTree
{
}
public virtual void pre_do_visit(desugared_deconstruction _desugared_deconstruction)
{
}
public virtual void post_do_visit(desugared_deconstruction _desugared_deconstruction)
{
}
public override void visit(expression _expression)
{
DefaultVisit(_expression);
@ -3819,6 +3827,15 @@ namespace PascalABCCompiler.SyntaxTree
visit(pattern_deconstructor_parameter.type);
post_do_visit(_pattern_deconstructor_parameter);
}
public override void visit(desugared_deconstruction _desugared_deconstruction)
{
DefaultVisit(_desugared_deconstruction);
pre_do_visit(_desugared_deconstruction);
for (int i = 0; i < definitions.Count; i++)
visit(desugared_deconstruction.definitions[i]);
post_do_visit(_desugared_deconstruction);
}
}

View file

@ -480,6 +480,8 @@ namespace PascalABCCompiler.SyntaxTree
return new deconstructor_pattern();
case 229:
return new pattern_deconstructor_parameter();
case 230:
return new desugared_deconstruction();
}
return null;
}
@ -4062,6 +4064,31 @@ namespace PascalABCCompiler.SyntaxTree
_pattern_deconstructor_parameter.type = _read_node() as type_definition;
}
public void visit(desugared_deconstruction _desugared_deconstruction)
{
read_desugared_deconstruction(_desugared_deconstruction);
}
public void read_desugared_deconstruction(desugared_deconstruction _desugared_deconstruction)
{
read_statement(_desugared_deconstruction);
if (br.ReadByte() == 0)
{
_desugared_deconstruction.definitions = null;
}
else
{
_desugared_deconstruction.definitions = new List<var_def_statement>();
Int32 ssyy_count = br.ReadInt32();
for(Int32 ssyy_i = 0; ssyy_i < ssyy_count; ssyy_i++)
{
_desugared_deconstruction.definitions.Add(_read_node() as var_def_statement);
}
}
_desugared_deconstruction.deconstruction_target = (object)br.ReadByte();
}
}

View file

@ -6385,6 +6385,40 @@ namespace PascalABCCompiler.SyntaxTree
}
}
public void visit(desugared_deconstruction _desugared_deconstruction)
{
bw.Write((Int16)230);
write_desugared_deconstruction(_desugared_deconstruction);
}
public void write_desugared_deconstruction(desugared_deconstruction _desugared_deconstruction)
{
write_statement(_desugared_deconstruction);
if (_desugared_deconstruction.definitions == null)
{
bw.Write((byte)0);
}
else
{
bw.Write((byte)1);
bw.Write(_desugared_deconstruction.definitions.Count);
for(Int32 ssyy_i = 0; ssyy_i < _desugared_deconstruction.definitions.Count; ssyy_i++)
{
if (_desugared_deconstruction.definitions[ssyy_i] == null)
{
bw.Write((byte)0);
}
else
{
bw.Write((byte)1);
_desugared_deconstruction.definitions[ssyy_i].visit(this);
}
}
}
bw.Write((byte)_desugared_deconstruction.deconstruction_target);
}
}

View file

@ -49132,6 +49132,356 @@ namespace PascalABCCompiler.SyntaxTree
}
///<summary>
///Представляет объединение объявлений пременных, порожденных деконструкцией. Деконструируемое выражение необходимо хранить для выведения типа на этапе семантики, однако оно не должно входить в обход дерева.
///</summary>
[Serializable]
public partial class desugared_deconstruction : statement
{
///<summary>
///Конструктор без параметров.
///</summary>
public desugared_deconstruction()
{
}
///<summary>
///Конструктор с параметрами.
///</summary>
public desugared_deconstruction(List<var_def_statement> _definitions,object _deconstruction_target)
{
this._definitions=_definitions;
this._deconstruction_target=_deconstruction_target;
FillParentsInDirectChilds();
}
///<summary>
///Конструктор с параметрами.
///</summary>
public desugared_deconstruction(List<var_def_statement> _definitions,object _deconstruction_target,SourceContext sc)
{
this._definitions=_definitions;
this._deconstruction_target=_deconstruction_target;
source_context = sc;
FillParentsInDirectChilds();
}
public desugared_deconstruction(var_def_statement elem, SourceContext sc = null)
{
Add(elem, sc);
FillParentsInDirectChilds();
}
protected List<var_def_statement> _definitions=new List<var_def_statement>();
protected object _deconstruction_target;
///<summary>
///Объявления порожденных переменных
///</summary>
public List<var_def_statement> definitions
{
get
{
return _definitions;
}
set
{
_definitions=value;
}
}
///<summary>
///Деконструируемое выражение
///</summary>
public object deconstruction_target
{
get
{
return _deconstruction_target;
}
set
{
_deconstruction_target=value;
}
}
public desugared_deconstruction Add(var_def_statement elem, SourceContext sc = null)
{
definitions.Add(elem);
if (elem != null)
elem.Parent = this;
if (sc != null)
source_context = sc;
return this;
}
public void AddFirst(var_def_statement el)
{
if (el == null)
throw new ArgumentNullException(nameof(el));
definitions.Insert(0, el);
FillParentsInDirectChilds();
}
public void AddFirst(IEnumerable<var_def_statement> els)
{
if (els == null)
throw new ArgumentNullException(nameof(els));
definitions.InsertRange(0, els);
foreach (var el in els)
if (el != null)
el.Parent = this;
}
public void AddMany(params var_def_statement[] els)
{
if (els == null)
throw new ArgumentNullException(nameof(els));
definitions.AddRange(els);
foreach (var el in els)
if (el != null)
el.Parent = this;
}
private int FindIndexInList(var_def_statement el)
{
if (el == null)
throw new ArgumentNullException(nameof(el));
var ind = definitions.FindIndex(x => x == el);
if (ind == -1)
throw new Exception(string.Format("У списка {0} не найден элемент {1} среди дочерних\n", this, el));
return ind;
}
public void InsertAfter(var_def_statement el, var_def_statement newel)
{
if (el == null)
throw new ArgumentNullException(nameof(el));
if (newel == null)
throw new ArgumentNullException(nameof(newel));
definitions.Insert(FindIndexInList(el) + 1, newel);
newel.Parent = this;
}
public void InsertAfter(var_def_statement el, IEnumerable<var_def_statement> newels)
{
if (el == null)
throw new ArgumentNullException(nameof(el));
if (newels == null)
throw new ArgumentNullException(nameof(newels));
definitions.InsertRange(FindIndexInList(el) + 1, newels);
foreach (var newel in newels)
if (newel != null)
newel.Parent = this;
}
public void InsertBefore(var_def_statement el, var_def_statement newel)
{
if (el == null)
throw new ArgumentNullException(nameof(el));
if (newel == null)
throw new ArgumentNullException(nameof(newel));
definitions.Insert(FindIndexInList(el), newel);
newel.Parent = this;
}
public void InsertBefore(var_def_statement el, IEnumerable<var_def_statement> newels)
{
if (el == null)
throw new ArgumentNullException(nameof(el));
if (newels == null)
throw new ArgumentNullException(nameof(newels));
definitions.InsertRange(FindIndexInList(el), newels);
foreach (var newel in newels)
if (newel != null)
newel.Parent = this;
}
public bool Remove(var_def_statement el)
{
return definitions.Remove(el);
}
public void ReplaceInList(var_def_statement el, var_def_statement newel)
{
if (el == null)
throw new ArgumentNullException(nameof(el));
if (newel == null)
throw new ArgumentNullException(nameof(newel));
definitions[FindIndexInList(el)] = newel;
newel.Parent = this;
}
public void ReplaceInList(var_def_statement el, IEnumerable<var_def_statement> newels)
{
if (el == null)
throw new ArgumentNullException(nameof(el));
if (newels == null)
throw new ArgumentNullException(nameof(newels));
var ind = FindIndexInList(el);
definitions.RemoveAt(ind);
definitions.InsertRange(ind, newels);
foreach (var newel in newels)
if (newel != null)
newel.Parent = this;
}
public int RemoveAll(Predicate<var_def_statement> match)
{
return definitions.RemoveAll(match);
}
public var_def_statement Last()
{
if (definitions.Count > 0)
return definitions[definitions.Count - 1];
throw new InvalidOperationException("Список пуст");
}
public int Count
{
get { return definitions.Count; }
}
public void Insert(int pos, var_def_statement el)
{
if (el == null)
throw new ArgumentNullException(nameof(el));
definitions.Insert(pos,el);
if (el != null)
el.Parent = this;
}
/// <summary> Создает копию узла </summary>
public override syntax_tree_node Clone()
{
desugared_deconstruction copy = new desugared_deconstruction();
copy.Parent = this.Parent;
if (source_context != null)
copy.source_context = new SourceContext(source_context);
if (attributes != null)
{
copy.attributes = (attribute_list)attributes.Clone();
copy.attributes.Parent = copy;
}
if (definitions != null)
{
foreach (var_def_statement elem in definitions)
{
if (elem != null)
{
copy.Add((var_def_statement)elem.Clone());
copy.Last().Parent = copy;
}
else
copy.Add(null);
}
}
copy.deconstruction_target = deconstruction_target;
return copy;
}
/// <summary> Получает копию данного узла корректного типа </summary>
public new desugared_deconstruction TypedClone()
{
return Clone() as desugared_deconstruction;
}
///<summary> Заполняет поля Parent в непосредственных дочерних узлах </summary>
public override void FillParentsInDirectChilds()
{
if (attributes != null)
attributes.Parent = this;
if (definitions != null)
{
foreach (var child in definitions)
if (child != null)
child.Parent = this;
}
}
///<summary> Заполняет поля Parent во всем поддереве </summary>
public override void FillParentsInAllChilds()
{
FillParentsInDirectChilds();
attributes?.FillParentsInAllChilds();
if (definitions != null)
{
foreach (var child in definitions)
child?.FillParentsInAllChilds();
}
}
///<summary>
///Свойство для получения количества всех подузлов без элементов поля типа List
///</summary>
public override Int32 subnodes_without_list_elements_count
{
get
{
return 0;
}
}
///<summary>
///Свойство для получения количества всех подузлов. Подузлом также считается каждый элемент поля типа List
///</summary>
public override Int32 subnodes_count
{
get
{
return 0 + (definitions == null ? 0 : definitions.Count);
}
}
///<summary>
///Индексатор для получения всех подузлов
///</summary>
public override syntax_tree_node this[Int32 ind]
{
get
{
if(subnodes_count == 0 || ind < 0 || ind > subnodes_count-1)
throw new IndexOutOfRangeException();
Int32 index_counter=ind - 0;
if(definitions != null)
{
if(index_counter < definitions.Count)
{
return definitions[index_counter];
}
}
return null;
}
set
{
if(subnodes_count == 0 || ind < 0 || ind > subnodes_count-1)
throw new IndexOutOfRangeException();
Int32 index_counter=ind - 0;
if(definitions != null)
{
if(index_counter < definitions.Count)
{
definitions[index_counter]= (var_def_statement)value;
return;
}
}
}
}
///<summary>
///Метод для обхода дерева посетителем
///</summary>
///<param name="visitor">Объект-посетитель.</param>
///<returns>Return value is void</returns>
public override void visit(IVisitor visitor)
{
visitor.visit(this);
}
}
}

View file

@ -2,6 +2,7 @@
using System.Text;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
namespace PascalABCCompiler.SyntaxTree
{
@ -324,6 +325,9 @@ namespace PascalABCCompiler.SyntaxTree
public void AddMany(IEnumerable<statement> els)
{
list.AddRange(els);
foreach (var elem in els)
if (elem != null)
elem.Parent = this;
}
public static statement_list Empty
@ -1273,40 +1277,32 @@ namespace PascalABCCompiler.SyntaxTree
public partial class var_statement
{
public var_statement(ident_list vars, type_definition type, expression iv)
public var_statement(ident_list vars, type_definition type, expression iv) : this(new var_def_statement(vars, type, iv))
{
var_def = new var_def_statement(vars, type, iv);
}
public var_statement(ident_list vars, type_definition type)
public var_statement(ident_list vars, type_definition type): this(new var_def_statement(vars, type))
{
var_def = new var_def_statement(vars, type);
}
public var_statement(ident id, type_definition type, expression iv)
public var_statement(ident id, type_definition type, expression iv) : this(new var_def_statement(new ident_list(id), type, iv))
{
var_def = new var_def_statement(new ident_list(id), type, iv);
}
public var_statement(ident id, type_definition type)
public var_statement(ident id, type_definition type) : this(new var_def_statement(new ident_list(id), type))
{
var_def = new var_def_statement(new ident_list(id), type);
}
public var_statement(ident id, string type)
public var_statement(ident id, string type) : this(new var_def_statement(new ident_list(id), new named_type_reference(type)))
{
var_def = new var_def_statement(new ident_list(id), new named_type_reference(type));
}
public var_statement(ident id, expression iv)
public var_statement(ident id, expression iv) :this(new var_def_statement(new ident_list(id), null, iv))
{
var_def = new var_def_statement(new ident_list(id), null, iv);
}
public var_statement(ident id, expression iv,SourceContext sc)
public var_statement(ident id, expression iv,SourceContext sc) : this(new var_def_statement(new ident_list(id), null, iv, sc))
{
var_def = new var_def_statement(new ident_list(id), null, iv);
var_def.source_context = sc;
}
public override string ToString()
@ -1747,6 +1743,23 @@ namespace PascalABCCompiler.SyntaxTree
public override string ToString() => "lam_inferred";
}
public partial class desugared_deconstruction
{
public bool HasAllExplicitTypes => definitions.All(x => x.vars_type != null);
public var_statement[] WithTypes(type_definition[] types)
{
var_statement[] result = new var_statement[types.Length];
Debug.Assert(types.Length == definitions.Count, "Inconsistent types count");
for (int i = 0; i < definitions.Count; i++)
{
definitions[i].vars_type = types[i];
result[i] = new var_statement(definitions[i]);
}
return result;
}
}
}

View file

@ -1384,6 +1384,12 @@ namespace PascalABCCompiler.SyntaxTree
///<param name="_pattern_deconstructor_parameter">Node to visit</param>
///<returns> Return value is void </returns>
void visit(pattern_deconstructor_parameter _pattern_deconstructor_parameter);
///<summary>
///Method to visit desugared_deconstruction.
///</summary>
///<param name="_desugared_deconstruction">Node to visit</param>
///<returns> Return value is void </returns>
void visit(desugared_deconstruction _desugared_deconstruction);
}

View file

@ -2859,8 +2859,12 @@
<Fields />
<Methods />
<Tags>
<CategoryIndices />
<TagIndices />
<CategoryIndices>
<CategoryIndex>0</CategoryIndex>
</CategoryIndices>
<TagIndices>
<TagIndex>9</TagIndex>
</TagIndices>
</Tags>
</SyntaxNode>
<SyntaxNode Name="type_pattern" BaseName="pattern_node">
@ -2870,8 +2874,12 @@
</Fields>
<Methods />
<Tags>
<CategoryIndices />
<TagIndices />
<CategoryIndices>
<CategoryIndex>0</CategoryIndex>
</CategoryIndices>
<TagIndices>
<TagIndex>9</TagIndex>
</TagIndices>
</Tags>
</SyntaxNode>
<SyntaxNode Name="is_pattern_expr" BaseName="expression">
@ -2881,8 +2889,12 @@
</Fields>
<Methods />
<Tags>
<CategoryIndices />
<TagIndices />
<CategoryIndices>
<CategoryIndex>0</CategoryIndex>
</CategoryIndices>
<TagIndices>
<TagIndex>9</TagIndex>
</TagIndices>
</Tags>
</SyntaxNode>
<SyntaxNode Name="match_with" BaseName="statement">
@ -2892,8 +2904,12 @@
</Fields>
<Methods />
<Tags>
<CategoryIndices />
<TagIndices />
<CategoryIndices>
<CategoryIndex>0</CategoryIndex>
</CategoryIndices>
<TagIndices>
<TagIndex>9</TagIndex>
</TagIndices>
</Tags>
</SyntaxNode>
<SyntaxNode Name="pattern_case" BaseName="statement">
@ -2904,8 +2920,12 @@
</Fields>
<Methods />
<Tags>
<CategoryIndices />
<TagIndices />
<CategoryIndices>
<CategoryIndex>0</CategoryIndex>
</CategoryIndices>
<TagIndices>
<TagIndex>9</TagIndex>
</TagIndices>
</Tags>
</SyntaxNode>
<SyntaxNode Name="pattern_cases" BaseName="statement">
@ -2914,8 +2934,12 @@
</Fields>
<Methods />
<Tags>
<CategoryIndices />
<TagIndices />
<CategoryIndices>
<CategoryIndex>0</CategoryIndex>
</CategoryIndices>
<TagIndices>
<TagIndex>9</TagIndex>
</TagIndices>
</Tags>
</SyntaxNode>
<SyntaxNode Name="deconstructor_pattern" BaseName="pattern_node">
@ -2925,8 +2949,12 @@
</Fields>
<Methods />
<Tags>
<CategoryIndices />
<TagIndices />
<CategoryIndices>
<CategoryIndex>0</CategoryIndex>
</CategoryIndices>
<TagIndices>
<TagIndex>9</TagIndex>
</TagIndices>
</Tags>
</SyntaxNode>
<SyntaxNode Name="pattern_deconstructor_parameter" BaseName="syntax_tree_node">
@ -2936,8 +2964,27 @@
</Fields>
<Methods />
<Tags>
<CategoryIndices />
<TagIndices />
<CategoryIndices>
<CategoryIndex>0</CategoryIndex>
</CategoryIndices>
<TagIndices>
<TagIndex>9</TagIndex>
</TagIndices>
</Tags>
</SyntaxNode>
<SyntaxNode Name="desugared_deconstruction" BaseName="statement">
<Fields>
<ExtendedField Name="definitions" Type="List&lt;var_def_statement&gt;" CreateVariable="true" DeleteVariable="false" />
<ExtendedField Name="deconstruction_target" Type="object" CreateVariable="false" DeleteVariable="false" />
</Fields>
<Methods />
<Tags>
<CategoryIndices>
<CategoryIndex>0</CategoryIndex>
</CategoryIndices>
<TagIndices>
<TagIndex>9</TagIndex>
</TagIndices>
</Tags>
</SyntaxNode>
</SyntaxNodes>
@ -2965,6 +3012,7 @@
<Tag Name="Важнейшие" ReferenceCount="207" />
<Tag Name="Method_Procedure_Call" ReferenceCount="2" />
<Tag Name="Yield" ReferenceCount="8" />
<Tag Name="Patterns" ReferenceCount="9" />
</Tags>
</FilterCategory>
</TagCategories>
@ -3280,6 +3328,12 @@
<HelpData Key="dereference.dereferencing_value" Value="" />
<HelpData Key="dereference.override string ToString()" Value="" />
<HelpData Key="destructor" Value="" />
<HelpData Key="desugared_deconstruction" Value="Представляет объединение объявлений пременных, порожденных деконструкцией. Деконструируемое выражение необходимо хранить для выведения типа на этапе семантики, однако оно не должно входить в обход дерева." />
<HelpData Key="desugared_deconstruction.deconstruct_call" Value="Вызов метода Deconstruct" />
<HelpData Key="desugared_deconstruction.deconstruction_target" Value="Деконструируемое выражение" />
<HelpData Key="desugared_deconstruction.definitions" Value="Объявления порожденных переменных" />
<HelpData Key="desugared_deconstruction.destruct_call" Value="" />
<HelpData Key="desugared_deconstruction.expressionVariableName" Value="Деконструируемое выражение" />
<HelpData Key="diap_expr" Value="" />
<HelpData Key="diap_expr." Value="" />
<HelpData Key="diap_expr.left" Value="" />
@ -4235,6 +4289,8 @@
<HelpData Key="unknown_ident" Value="" />
<HelpData Key="unknown_ident.ClassName" Value="" />
<HelpData Key="unknown_ident.UnknownID" Value="" />
<HelpData Key="unknown_type" Value="" />
<HelpData Key="unknown_type.context" Value="" />
<HelpData Key="unnamed_type_object" Value="Это - сахарная конструкция.&#xD;&#xA;/// Объект безымянного класса. Например: new class(Name := 'Иванов'; Age := 25);&#xD;&#xA;/// ne - это узел для генерации кода, основной узел предназначен для форматирования" />
<HelpData Key="unnamed_type_object.is_class" Value="" />
<HelpData Key="unnamed_type_object.ne" Value="" />

View file

@ -8,8 +8,41 @@ using PascalABCCompiler.TreeConversion;
namespace SyntaxVisitors.SugarVisitors
{
public class DeconstructionDesugaringResult
{
/// <summary>
/// Переменная, имеющая тип паттерна
/// </summary>
public var_statement CastVariableDefinition { get; set; }
/// <summary>
/// Переменные, полученные в результате деконструкции
/// </summary>
public List<var_def_statement> DeconstructionVariables { get; private set; } = new List<var_def_statement>();
/// <summary>
/// Проверка соответствия типа выражения типу паттерна
/// </summary>
public expression TypeCastCheck { get; set; }
/// <summary>
/// Вызов Deconstruct
/// </summary>
public statement DeconstructCall { get; set; }
public ident CastVariable
{
get
{
return CastVariableDefinition.var_def.vars.list[0];
}
}
}
public class MatchWithVisitor : BaseChangeVisitor
{
private const string DeconstructMethodName = "Deconstruct";
private int _variableCounter = 0;
private if_node _previousIf;
private statement_list desugaredMatchWith;
@ -28,6 +61,7 @@ namespace SyntaxVisitors.SugarVisitors
DesugarTypePatternCase(matchWith.expr, patternCase);
if (patternCase.pattern is deconstructor_pattern)
// TODO: introduce a variable for expression and cache it
DesugarDeconstructorPatternCase(matchWith.expr, patternCase);
}
@ -43,35 +77,31 @@ namespace SyntaxVisitors.SugarVisitors
{
Debug.Assert(patternCase.pattern is type_pattern);
var result = new statement_list();
// создание фиктивной переменной необходимого типа
var pattern = (type_pattern) patternCase.pattern;
var matchResultVariableName = GenerateIdent();
result.Add(new var_statement(matchResultVariableName, pattern.type));
// делегирование проверки паттерна функции IsTest
var isTest = SubtreeCreator.CreateSystemFunctionCall("IsTest", matchingExpression, matchResultVariableName);
//var result = new statement_list();
//// создание фиктивной переменной необходимого типа
//var pattern = (type_pattern) patternCase.pattern;
// Конструируем условие мэтчинга
expression matchCondition = isTest;
if (patternCase.condition == null)
matchCondition = isTest;
else
// Если есть секция when - добавляем ее в условие
{
// Переименовываем идентификатор, т.к. мы сгенерировали внутреннее имя
patternCase.condition.RenameIdentifierInDescendants(pattern.identifier.name, matchResultVariableName.name);
matchCondition = new bin_expr(isTest, patternCase.condition, Operators.LogicalAND);
}
//// Конструируем условие мэтчинга
//expression matchCondition = isTest;
//if (patternCase.condition == null)
// matchCondition = isTest;
//else
//// Если есть секция when - добавляем ее в условие
//{
// // Переименовываем идентификатор, т.к. мы сгенерировали внутреннее имя
// patternCase.condition.RenameIdentifierInDescendants(pattern.identifier.name, matchResultVariableName.name);
// matchCondition = new bin_expr(isTest, patternCase.condition, Operators.LogicalAND);
//}
// Создание узла if с объявлением переменной из паттерна и присвоение ей значения
// сгенерированной переменной
var patternVarDef = new var_statement(pattern.identifier, matchResultVariableName);
// Создание тела if из объявления переменной и соттветствующего тела case
var ifCheck = SubtreeCreator.CreateIf(matchCondition, new statement_list(patternVarDef, patternCase.case_action));
result.Add(ifCheck);
//// Создание узла if с объявлением переменной из паттерна и присвоение ей значения
//// сгенерированной переменной
//var patternVarDef = new var_statement(pattern.identifier, matchResultVariableName);
//// Создание тела if из объявления переменной и соттветствующего тела case
//var ifCheck = SubtreeCreator.CreateIf(matchCondition, new statement_list(patternVarDef, patternCase.case_action));
//result.Add(ifCheck);
// Добавляем полученные statements в результат
AddDesugaredCaseToResult(result, ifCheck);
//// Добавляем полученные statements в результат
//AddDesugaredCaseToResult(result, ifCheck);
}
void DesugarDeconstructorPatternCase(expression matchingExpression, pattern_case patternCase)
@ -79,30 +109,24 @@ namespace SyntaxVisitors.SugarVisitors
Debug.Assert(patternCase.pattern is deconstructor_pattern);
var result = new statement_list();
var pattern = patternCase.pattern as deconstructor_pattern;
// создание фиктивной переменной необходимого типа
var pattern = (deconstructor_pattern)patternCase.pattern;
var matchResultVariableName = GenerateIdent();
result.Add(new var_statement(matchResultVariableName, pattern.type));
// делегирование проверки паттерна функции IsTest
var isTest = SubtreeCreator.CreateSystemFunctionCall("IsTest", matchingExpression, matchResultVariableName);
var desugaredPattern = DesugarPattern(pattern, matchingExpression);
result.Add(desugaredPattern.CastVariableDefinition);
// Конструируем условие мэтчинга
expression matchCondition = isTest;
if (patternCase.condition == null)
matchCondition = isTest;
else
if (patternCase.condition != null)
// Если есть секция when - добавляем ее в условие
{
// Переименовываем идентификатор, т.к. мы сгенерировали внутреннее имя
patternCase.condition.RenameIdentifierInDescendants(pattern.parameters[0].identifier.name, matchResultVariableName.name);
matchCondition = new bin_expr(isTest, patternCase.condition, Operators.LogicalAND);
// TODO: generate check for 'when'
}
// Создание узла if с объявлением переменной из паттерна и присвоение ей значения
// сгенерированной переменной
var patternVarDef = new var_statement(pattern.parameters[0].identifier.name, matchResultVariableName);
// Создание тела if из объявления переменной и соттветствующего тела case
var ifCheck = SubtreeCreator.CreateIf(matchCondition, new statement_list(patternVarDef, patternCase.case_action));
// Создание тела if из объявлений переменных, вызова Deconstruct и соответствующего тела case
var ifBody = new statement_list();
ifBody.Add(new desugared_deconstruction(desugaredPattern.DeconstructionVariables, desugaredPattern.CastVariable));
ifBody.Add(desugaredPattern.DeconstructCall);
ifBody.Add(patternCase.case_action);
var ifCheck = SubtreeCreator.CreateIf(desugaredPattern.TypeCastCheck, ifBody);
result.Add(ifCheck);
// Добавляем полученные statements в результат
@ -125,5 +149,25 @@ namespace SyntaxVisitors.SugarVisitors
// Запоминаем только что сгенерированный if
_previousIf = newIf;
}
private DeconstructionDesugaringResult DesugarPattern(deconstructor_pattern pattern, expression matchingExpression)
{
var desugarResult = new DeconstructionDesugaringResult();
var castVariableName = GenerateIdent();
desugarResult.CastVariableDefinition = new var_statement(castVariableName, pattern.type);
// делегирование проверки паттерна функции IsTest
desugarResult.TypeCastCheck = SubtreeCreator.CreateSystemFunctionCall("IsTest", matchingExpression, castVariableName);
foreach (var deconstructedVariable in pattern.parameters)
desugarResult.DeconstructionVariables.Add(
new var_def_statement(deconstructedVariable.identifier, deconstructedVariable.type));
var deconstructCall = new procedure_call();
deconstructCall.func_name = SubtreeCreator.CreateMethodCall(DeconstructMethodName, castVariableName.name, pattern.parameters.Select(x => x.identifier).ToArray());
desugarResult.DeconstructCall = deconstructCall;
return desugarResult;
}
}
}

View file

@ -107,11 +107,7 @@ namespace PascalABCCompiler.TreeConversion
private static SyntaxTree.if_node CreateIfElse(expression condition, statement thenBody, statement elseBody)
{
SyntaxTree.if_node res = new SyntaxTree.if_node();
res.condition = condition;
res.then_body = thenBody;
res.else_body = elseBody;
return res;
return new SyntaxTree.if_node(condition, thenBody, elseBody);
}
/// <summary>
@ -193,9 +189,14 @@ namespace PascalABCCompiler.TreeConversion
/// <param name="exprList">Параметры функции</param>
/// <returns></returns>
public static method_call CreateSystemFunctionCall(string funcName, params expression[] exprList)
{
return CreateMethodCall(funcName, "PABCSystem", exprList);
}
public static method_call CreateMethodCall(string funcName, string qualifier, params expression[] exprList)
{
var methodCall = CreateMethodCall(funcName, exprList);
methodCall.dereferencing_value = new dot_node(new ident("PABCSystem"), new ident(funcName));
methodCall.dereferencing_value = new dot_node(new ident(qualifier), new ident(funcName));
return methodCall;
}

View file

@ -2,18 +2,13 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PascalABCCompiler.SyntaxTree;
using PascalABCCompiler.TreeRealization;
namespace PascalABCCompiler.TreeConverter
{
public partial class syntax_tree_visitor
{
public override void visit(SyntaxTree.pattern_case _pattern_case)
{
CheckWhenExpression(_pattern_case.condition);
}
private void CheckWhenExpression(SyntaxTree.expression when)
{
if (when == null)
@ -23,5 +18,58 @@ namespace PascalABCCompiler.TreeConverter
if (!convertion_data_and_alghoritms.can_convert_type(convertedWhen, SystemLibrary.SystemLibrary.bool_type))
AddError(get_location(when), "WHEN_EXPRESSION_SHOULD_HAVE_BOOL_TYPE");
}
public override void visit(desugared_deconstruction deconstruction)
{
if (deconstruction.HasAllExplicitTypes)
{
foreach (var def in deconstruction.definitions.Select(x => new var_statement(x)))
def.visit(this);
return;
}
var invokationTarget = convert_strong(deconstruction.deconstruction_target as expression);
var types = InferPatternVariableType(deconstruction.definitions, invokationTarget, deconstruction);
if (types == null)
return;
foreach (var definition in deconstruction.WithTypes(types.Select(x => new semantic_type_node(x)).ToArray()))
definition.visit(this);
}
private type_node[] InferPatternVariableType(List<var_def_statement> variableDefinitions, expression_node targetExpression, desugared_deconstruction deconstruction)
{
var castType = targetExpression.type as common_type_node;
var candidates = castType.methods.Where(x => x.name.ToLower() == "deconstruct").ToList();
var deconstructParametersCount = variableDefinitions.Count;
parameter_list deconstructionParameters = null;
int suitableCandidates = 0;
foreach (var candidate in candidates)
{
if (candidate.parameters.Count != deconstructParametersCount)
continue;
deconstructionParameters = candidate.parameters;
suitableCandidates++;
}
type_node[] result = null;
if (suitableCandidates == 0)
{
if (deconstructParametersCount > 1)
AddError(get_location(deconstruction), "NO_SUITABLE_DECONSTRUCT_FOUND");
else
result = new[] { targetExpression.type };
}
else
{
if (suitableCandidates > 1)
AddError(get_location(deconstruction), "DECONSTRUCTOR_METHOD_AMBIGUITY");
else
result = deconstructionParameters.Select(x => x.type).ToArray();
}
return result;
}
}
}