Lowering для foreach: различия между версиями

Материал из Вики проекта PascalABC.NET
Перейти к навигацииПерейти к поиску
Нет описания правки
Нет описания правки
Строка 9: Строка 9:


<source lang="Delphi">
<source lang="Delphi">
var a: IEnumerable<auto_foreach> := l;
var a: IEnumerable<yield_unknown_foreach_type> := l;
    
    
var en := a.GetEnumerator();
var en := a.GetEnumerator();
var curr: auto_foreach; // или эта переменная была описана ранее если foreach x
while en.MoveNext do
while en.MoveNext do
begin
begin
   curr := en.Current;
   var curr := en.Current;
   Print(curr);
   Print(curr);
end;
end;
Строка 24: Строка 23:
После этого генератор yield преобразует синтаксическое дерево так, что строка:
После этого генератор yield преобразует синтаксическое дерево так, что строка:
<source lang="Delphi">
<source lang="Delphi">
var a: IEnumerable<auto_foreach> := l;
var a: IEnumerable<yield_unknown_foreach_type> := l;
</source>
</source>


Строка 30: Строка 29:
<source lang="Delphi">
<source lang="Delphi">
// поле специального класса
// поле специального класса
a: IEnumerable<auto_foreach>
a: IEnumerable<yield_unknown_foreach_type>
...
...
// оператор в методе MoveNext этого класса
// оператор в методе MoveNext этого класса
Строка 38: Строка 37:
===Основная идея===
===Основная идея===


Основная идея - ввести семантический тип auto_type, который перевычисляется при первом присваивании переменной этого типа
Основная идея автоопределния типа в yield - ввести семантический тип auto_type, который перевычисляется при первом присваивании переменной этого типа
 
Для IEnumerable<yield_unknown_foreach_type> она трансформируется следующим образом: yield_unknown_foreach_type на семантике преобразуется в ienumerable_auto_type.
При обработке присваивания на семантике если тип в левой части - IEnumerable<ienumerable_auto_type>, то он преобразуется к типу правой части в момент первого присваивания
(это произойдёт в теле метода MoveNext())


===Реализация в syntax_tree_visitor.cs ===
===Реализация в syntax_tree_visitor.cs ===


Так вот, auto_foreach при преобразовании синтаксиса в семантику переводится в специальный семантический тип auto_type, который исправляется в момент первого присваивания переменной a.
Так вот, yield_unknown_foreach_type при преобразовании синтаксиса в семантику переводится в специальный семантический тип auto_type, который исправляется в момент первого присваивания переменной a.
Таким образом, в syntax_tree_visitor.cs в  
Таким образом, в syntax_tree_visitor.cs в  



Версия от 14:49, 5 июля 2016

Такой код

foreach var x in l do
  Print(x);

заменяется на

var a: IEnumerable<yield_unknown_foreach_type> := l;
  
var en := a.GetEnumerator();
while en.MoveNext do
begin
  var curr := en.Current;
  Print(curr);
end;

на синтаксическом уровне.

После этого генератор yield преобразует синтаксическое дерево так, что строка:

var a: IEnumerable<yield_unknown_foreach_type> := l;

преобразуется в

// поле специального класса
a: IEnumerable<yield_unknown_foreach_type>
...
// оператор в методе MoveNext этого класса
a := l;

Основная идея

Основная идея автоопределния типа в yield - ввести семантический тип auto_type, который перевычисляется при первом присваивании переменной этого типа

Для IEnumerable<yield_unknown_foreach_type> она трансформируется следующим образом: yield_unknown_foreach_type на семантике преобразуется в ienumerable_auto_type. При обработке присваивания на семантике если тип в левой части - IEnumerable<ienumerable_auto_type>, то он преобразуется к типу правой части в момент первого присваивания (это произойдёт в теле метода MoveNext())

Реализация в syntax_tree_visitor.cs

Так вот, yield_unknown_foreach_type при преобразовании синтаксиса в семантику переводится в специальный семантический тип auto_type, который исправляется в момент первого присваивания переменной a. Таким образом, в syntax_tree_visitor.cs в

public override void visit(SyntaxTree.assign _assign)

будет код, аналогичный автоопределению типа в момент первого присваивания для переменных типа auto_type:

public override void visit(SyntaxTree.assign _assign)
{
  ...
  if (to.type is auto_type)
  {
    if (to is class_field_reference)
    {
      var cfr = to as class_field_reference;
      cfr.field.type = from.type;
    }
    else if (to is local_block_variable_reference)
    {
      var lvr = to as local_block_variable_reference;
      lvr.var.type = from.type;
    }
    else AddError(to.location, "Не могу вывести тип при наличии yield: "+ to.type.full_name);
    //to.type = from.type; // и без всякого real_type!
  }