Implement deconstruction, simple case
This commit is contained in:
parent
ed621517f3
commit
9d3fd3e5aa
|
|
@ -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;
|
||||
|
|
@ -1157,6 +1157,11 @@ namespace PascalABCCompiler.SyntaxTree
|
|||
{
|
||||
DefaultVisit(_pattern_deconstructor_parameter);
|
||||
}
|
||||
|
||||
public virtual void visit(desugared_deconstruction _desugared_deconstruction)
|
||||
{
|
||||
DefaultVisit(_desugared_deconstruction);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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<var_def_statement>" 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="Это - сахарная конструкция.
/// Объект безымянного класса. Например: new class(Name := 'Иванов'; Age := 25);
/// ne - это узел для генерации кода, основной узел предназначен для форматирования" />
|
||||
<HelpData Key="unnamed_type_object.is_class" Value="" />
|
||||
<HelpData Key="unnamed_type_object.ne" Value="" />
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue