Lowering для foreach

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

Такой код

foreach var x in l do
  Print(x);

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

var a: IEnumerable<auto_foreach> := l;
  
var en := a.GetEnumerator();
var curr: auto_foreach; // или эта переменная была описана ранее если foreach x
while en.MoveNext do
begin
  curr := en.Current;
  Print(curr);
end;

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

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

var a: IEnumerable<auto_foreach> := l;

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

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

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

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

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

Так вот, auto_foreach при преобразовании синтаксиса в семантику переводится в специальный семантический тип 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!
  }