Lowering для foreach: различия между версиями
Mikst (обсуждение | вклад) Нет описания правки |
Mikst (обсуждение | вклад) Нет описания правки |
||
Строка 9: | Строка 9: | ||
<source lang="Delphi"> | <source lang="Delphi"> | ||
var a: IEnumerable< | var a: IEnumerable<yield_unknown_foreach_type> := l; | ||
var en := a.GetEnumerator(); | var en := a.GetEnumerator(); | ||
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< | var a: IEnumerable<yield_unknown_foreach_type> := l; | ||
</source> | </source> | ||
Строка 30: | Строка 29: | ||
<source lang="Delphi"> | <source lang="Delphi"> | ||
// поле специального класса | // поле специального класса | ||
a: IEnumerable< | 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 === | ||
Так вот, | Так вот, 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!
}