Engine

Делаю игровой движок, при попытке компиляции файлика Interpolators вылетает:

() : Внутренняя ошибка компилятора в модуле [pabcnetc.exe] :'System.Exception: System.NullReferenceException: Ссылка на объект не указывает на экземпляр объекта. в SyntaxVisitors.CollectClassFieldsVisitor.visit(class_definition cd) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.ProcessNode(syntax_tree_node Node) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.DefaultVisit(syntax_tree_node n) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.ProcessNode(syntax_tree_node Node) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.DefaultVisit(syntax_tree_node n) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.ProcessNode(syntax_tree_node Node) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.DefaultVisit(syntax_tree_node n) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.ProcessNode(syntax_tree_node Node) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.DefaultVisit(syntax_tree_node n) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.ProcessNode(syntax_tree_node Node) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.DefaultVisit(syntax_tree_node n) в SyntaxVisitors.ProcessYieldCapturedVarsVisitor.CollectClassFieldsNames(procedure_definition pd, ISet1 collectedFields) в SyntaxVisitors.ProcessYieldCapturedVarsVisitor.ReplaceCapturedVariables(procedure_definition pd, IEnumerable1 deletedLocals, IDictionary2& capturedLocalsNamesMap, IDictionary2& capturedFormalParamsNamesMap) в SyntaxVisitors.ProcessYieldCapturedVarsVisitor.visit(procedure_definition pd) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.ProcessNode(syntax_tree_node Node) в PascalABCCompiler.SyntaxTree.BaseChangeVisitor.DefaultVisit(syntax_tree_node n) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.ProcessNode(syntax_tree_node Node) в PascalABCCompiler.SyntaxTree.BaseChangeVisitor.DefaultVisit(syntax_tree_node n) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.ProcessNode(syntax_tree_node Node) в PascalABCCompiler.SyntaxTree.BaseChangeVisitor.DefaultVisit(syntax_tree_node n) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.ProcessNode(syntax_tree_node Node) в PascalABCCompiler.SyntaxTree.BaseChangeVisitor.DefaultVisit(syntax_tree_node n) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.ProcessNode(syntax_tree_node Node) в PascalABCCompiler.SyntaxTree.BaseChangeVisitor.DefaultVisit(syntax_tree_node n) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.ProcessNode(syntax_tree_node Node) в PascalABCCompiler.SyntaxTree.BaseChangeVisitor.DefaultVisit(syntax_tree_node n) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.ProcessNode(syntax_tree_node Node) в PascalABCCompiler.SyntaxTree.BaseChangeVisitor.DefaultVisit(syntax_tree_node n) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.ProcessNode(syntax_tree_node Node) в PascalABCCompiler.SyntaxTree.BaseChangeVisitor.DefaultVisit(syntax_tree_node n) в PascalABCCompiler.SyntaxTree.WalkingVisitorNew.ProcessNode(syntax_tree_node Node) в PascalABCCompiler.SyntaxTreeConverters.StandardSyntaxTreeConverter.Convert(syntax_tree_node root) в PascalABCCompiler.SyntaxTreeConverters.SyntaxTreeConvertersController.Convert(syntax_tree_node root) в PascalABCCompiler.Compiler.CompileUnit(unit_node_list Units, unit_or_namespace SyntaxUsesUnit) в PascalABCCompiler.Compiler.Compile()

Движок.rar (2,4 МБ)

Описание и реализация класса в разных type сейчас запрещена:

type
  t1 = class;//Ошибка: Отсутствует описание типа t1

type
  t1 = class
    
  end;

begin end.

Конечно, компилятор ломаться не должен, но тут ваша ошибка, TInterpolator описан и реализован в разных type.

1 лайк

Поместил в одну секцию type:

Ах вот как… Что ж issue исправил… В общем не обязательно в разных type, главное чтоб у касса было пред описание. В общем попытайтесь без пред описания обойтись… Может сделать пред описание другому классу. Совета получше, я, пожалуй, не придумаю… Можно ещё конечно теперь ждать фикса, но это идея хуже…

В классе TModifier должны быть ссылки на TInterpolator, что без предописания сделать никак. Тем более TInterpolator использует TModifier.

Но можно ведь сделать наоборот, от того что сейчас. Сейчас так:

[пред описание TInterpolator]
[описание TModifier]
[описание TInterpolator]

Значит можно сделать так:

[пред описание TModifier]
[описание TInterpolator]
[описание TModifier]

А вообще лучше обычно делать пред описания всем классам, чтоб можно было реализовывать их в любом порядке, не зависимо от того в какой какой используется (ну, кроме наследования, там пред описание не пройдёт)

1 лайк
  1. Тогда же придется и всем наследникам от TModifier делать предописание. Разве нет?
  2. Я логически сгруппировал классы - сначала модификаторы, потом интерполяторы.

А вообще есть 1 способ… Вам нужно именно yield или может список подойдёт? Отличия:

function GetList:List<byte>;
begin
  writeln('Создаю список');
  Result := new List<byte>;//кстати можно сразу ещё и размер указать
  Result.Add(0);
  Result.Add(1);
  Result.Add(2);
end;

function GetSequence:sequence of byte;
begin
  writeln('Создаю последовательность');
  yield 0;
  yield 1;
  yield 2;
end;

begin
  var l := GetList;//"Создаю список" выведет тут
  var s := GetSequence;
  
  writeln(l);
  writeln(l);
  
  writeln(s);//"Создаю последовательность" выведет тут, а не там где была вызвана функция GetSequence
  writeln(s);//и тут ещё раз
end.

Когда речь заходит про sequence.ToArray (и ему подобных) - создаётся пустой массив и в него добавляются элементы по тому же алгоритму что и в List.Add.

А точнее

Создаётся пустой массив на 4 элемента, эти 4 элемента заполняет, если места не хватило - создаёт массив на 8 элементов, копирует в него элементы из предыдущего и продолжает. Если снова не хватило - снова создаёт в 2 раза больший массив и т.д. В самом конце (если вызвано как раз ToArray а не ToList) создаёт массив, по размеру совпадающий с количеством элементов и копирует в него элементы из последнего, типо отрезает лишнее.

Зато когда речь идёт о, к примеру, foreach - он не создаёт готовый массив, вместо этого он берёт по 1 значению, что то выполняет над ним, и удаляет. Ну и extensionmethod-ы типа TakeWhile не создают массив.

1 лайк

Нужен yield.

В последней версии не компилируется также…

А классы наследники TModifier тоже должны иметь предописание?

Не представляю как в вашей программе, но как я и сказал, это желательно, чтоб не важно было в каком порядке делать нормальное описание классов.

Сделал так, но я не могу использовать свойства объекта TModifier, так как его описание ниже TInterpolator.

Реализуйте функции использующие свойства TModifier - после его описания. Удобно сделать что то типа:

{$region TInterpolator}

//тут реализовывать методы TInterpolator

{$endregion TInterpolator}

В самом низу файла. Я лично делаю так для всех методов больших классов, чтоб, опять же, можно было не волноваться в каком порядке построены описания.

1 лайк

Для разных классов свои регионы?

Ну да. Если надо ещё под регионы можно делать. К примеру если класс очень большой - можно его описание и регион реализации методов разделить ещё несколькими регионами.

1 лайк

Что это за ошибка и почему она возникает:

Interpolators.pas(403) : SYNTAXTREEVISITORSERROR_Possible extension-method definintion without extensionmethod keyword. Please use extensionmethod syntax

?

Engine 5.2.5.rar (2,6 МБ)

Мда, конечно хорошо видно что yield не очень много использовали)) Иначе такие примитивные ошибки давно нашли бы…

interface-implementation в данном случае имеет только эстетический вид (в implementation можно добавить переменные, подпрограммы и типы, сделав их этим приватными, а раз у вас их нет - оно и не нужно), поэтому пока ошибку не исправят - уберите их.

1 лайк

Да, тут больше эстетика - во всех более менее больших или средних размеров модулях я использую interface-implementation. Баг, к счастью, выявился не в день сдачи проекта.