Это чья идея - Ваша? Основная ОС для .NET - это Windows и в ней по умолчанию используется UTF-16. Кроме того, в PacscalАВС.NЕТ изначально декларировалась совместимость с Delphi.
Ошибка идёт в вывод вместо списка ошибок:
## var a:=Arr(1);
Write(a[a.GetLowerBound]);
Тут надо начать с того, что это ошибка среды выполнения, как эта, а не куда её выводит.
Эта ошибка значит что компилятор сгенерировал не_выполняемый .exe файл. Такое сразу в новую issue.
В следующем обновлении консоль будет юникодной
Тема: идентификаторы.
## var a:=System.Globalization.UnicodeCategory.Format;
Программа не компилируется. При нажатии на кнопку “Сохранить отчёт как…” диалогового окна “Внутренняя ошибка компилятора”, оно бесконечно “Не отвечает”. Если открыть 2 таких окна, IDE бесконечно “Не отвечает”.
Кажется, ОК из-за того, что идентификаторы являются ключами, следовательно, не могут совпадать, а это происходит. Одинаковое имя имеют и константа перечисления, и функция Enum.Format.
Наверняка этот случай не единичный. Подпрограммы с аргументами можно отличать по наличию аргументов, а как — остальные идентификаторы? В таких случаях придётся терять совместимость со старыми версиями Pascal (в данном случае переименовать Enum.Format), поскольку потерять её с Microsoft.NET (в данном случае переименовать UnicodeCategory.Format) невозможно?
Отчёт
09.08.2021 3:06:11
PascalABCCompiler.Core v3.8.0.2949 (01.08.2021), debug version
Runtime version: 4.0.30319.42000
OS version: Microsoft Windows NT 10.0.19042.0
Processor count: 8
WorkingSet: 114360 kb
StatesList:
BeginCompileFile Program1.pas
BeginParsingFile Program1.pas
EndParsingFile Program1.pas
SyntaxTreeConversion Standard
ReadPCUFile PABCSystem.pcu
ReadDLL System.dll
ReadDLL mscorlib.dll
ReadDLL System.Core.dll
ReadDLL System.Numerics.dll
ReadPCUFile PABCExtensions.pcu
ReadPCUFile __RunMode.pcu
CompileInterface Program1.pas
CompilationFinished Program1.pas
Ready
Error[0]: Внутренняя ошибка компилятора в модуле [pabcnetc.exe] :'System.Exception: System.NullReferenceException: Ссылка на объект не указывает на экземпляр объекта.
в PascalABCCompiler.TreeConverter.convertion_data_and_alghoritms.function_eq_generic_params(function_node left, function_node right)
в PascalABCCompiler.TreeConverter.convertion_data_and_alghoritms.function_eq_params(function_node left, function_node right, Boolean compare_parameter_types)
в PascalABCCompiler.TreeConverter.convertion_data_and_alghoritms.find_eq_method_in_list(function_node fn, List`1 funcs)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.create_possible_delegates_list(expression_node obj, List`1 sil, location loc, Boolean is_static)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.make_delegate_wrapper(expression_node obj, List`1 sil, location loc, Boolean is_static)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.create_static_expression(type_node tn, ident id_right, List`1 si_right)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.dot_node_as_type_ident(type_node tn, ident id_right, motivation mot)
в PascalABCCompiler.TreeConverter.returner.visit(expression expr)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.convert_strong(expression expr)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(var_def_statement _var_def_statement)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(var_statement node)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.convert_strong(statement st)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(statement_list _statement_list)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.convert_strong(statement st)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit_program_code(statement_list program_code)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(block _block)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(program_module _program_module)
в PascalABCCompiler.TreeConverter.SyntaxTreeToSemanticTreeConverter.CompileInterface(compilation_unit SyntaxUnit, unit_node_list UsedUnits, List`1 ErrorsList, List`1 WarningsList, SyntaxError parser_error, Hashtable bad_nodes, using_namespace_list namespaces, Dictionary`2 docs, Boolean debug, Boolean debugging)
в PascalABCCompiler.Compiler.CompileUnit(unit_node_list Units, Dictionary`2 DirectCompilationUnits, unit_or_namespace SyntaxUsesUnit, String prev_path)
в PascalABCCompiler.Compiler.Compile() System.Exception: System.NullReferenceException: Ссылка на объект не указывает на экземпляр объекта.
в PascalABCCompiler.TreeConverter.convertion_data_and_alghoritms.function_eq_generic_params(function_node left, function_node right)
в PascalABCCompiler.TreeConverter.convertion_data_and_alghoritms.function_eq_params(function_node left, function_node right, Boolean compare_parameter_types)
в PascalABCCompiler.TreeConverter.convertion_data_and_alghoritms.find_eq_method_in_list(function_node fn, List`1 funcs)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.create_possible_delegates_list(expression_node obj, List`1 sil, location loc, Boolean is_static)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.make_delegate_wrapper(expression_node obj, List`1 sil, location loc, Boolean is_static)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.create_static_expression(type_node tn, ident id_right, List`1 si_right)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.dot_node_as_type_ident(type_node tn, ident id_right, motivation mot)
в PascalABCCompiler.TreeConverter.returner.visit(expression expr)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.convert_strong(expression expr)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(var_def_statement _var_def_statement)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(var_statement node)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.convert_strong(statement st)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(statement_list _statement_list)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.convert_strong(statement st)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit_program_code(statement_list program_code)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(block _block)
в PascalABCCompiler.TreeConverter.syntax_tree_visitor.visit(program_module _program_module)
в PascalABCCompiler.TreeConverter.SyntaxTreeToSemanticTreeConverter.CompileInterface(compilation_unit SyntaxUnit, unit_node_list UsedUnits, List`1 ErrorsList, List`1 WarningsList, SyntaxError parser_error, Hashtable bad_nodes, using_namespace_list namespaces, Dictionary`2 docs, Boolean debug, Boolean debugging)
в PascalABCCompiler.Compiler.CompileUnit(unit_node_list Units, Dictionary`2 DirectCompilationUnits, unit_or_namespace SyntaxUsesUnit, String prev_path)
в PascalABCCompiler.Compiler.Compile()'
Тема: гиперссылка нижнего колонтитула форума.
Вроде не битая по определению, но всё равно неприятно, но не знаю, куда обратиться:
Тема: переименование.
Не вникайте в нижеприведённый код, просто лень искать (Как называется самый маленький кусок кода, в котором воспроизводится ошибка? Вопрос не риторический.). Суть в том, что если нажать ПКМ на “i4” в строке for var i4 := 0 to a.Length - 1 do
, потом “Переименовать”, ввести “i3” и подтвердить, оно сработает не на все переменные. А тут — на все:
## var a:=0;
Write(a);
Контекст
/// Получает имя exe без пути и расширения
function GetOnlyEXEFileName: string;
begin
var a := LastPos('\', GetEXEFileName);
Result := GetEXEFileName.Substring(a, GetEXEFileName.Length - a - 4);
end;
/// Переводит t в русское обозначение
function DTtoR(t: System.DateTime) := t.Day.ToString + '.' + t.Month.ToString + '.' + t.Year.ToString + ' ' + t.TimeOfDay.ToString;
/// Записывает s в log
procedure WTF(s: string) := System.IO.File.AppendAllText(GetDir + '\' + GetOnlyEXEFileName + '.log', DTtoR(System.DateTime.Now) + ' ' + s + NewLine);
/// Изменяет размер окна и буфера консоли на w, h
procedure SCS(w, h: smallint);
begin
Console.WindowWidth := integer(w).Clamp(15, Console.LargestWindowWidth);
Console.BufferWidth := integer(w).Clamp(15, smallint.MaxValue - 1);
Console.WindowHeight := integer(h).Clamp(1, Console.LargestWindowHeight);
Console.BufferHeight := integer(h).Clamp(1, smallint.MaxValue - 1);
end;
/// Размер символа c в консоли. IPCIHS — являлся ли предыдущий выведенный символ верхней частью суррогатных пар.
function CCL(c: char; IPCIHS: boolean): smallint;
begin
if IPCIHS then
if char.IsHighSurrogate(c) then
Result := 1
else
case c of
char(7), char(8226): Result := 1;
char(8), char(9688): Result := 0;
char(9), char(9675):
begin
var NT: smallint := ((Console.CursorLeft + 1) div 8 + 1) * 8;
if (NT < Console.BufferWidth) then
Result := NT - Console.CursorLeft
else
Result := Console.BufferWidth - Console.CursorLeft + Min(8, Console.BufferWidth);
end;
char(10), char(9689): Result := Console.BufferWidth - Console.CursorLeft + (Console.CursorLeft = Console.BufferWidth - 1 ? Console.BufferWidth : 0);
char(13), char(9834): Result := Console.CursorLeft = Console.BufferWidth - 1 ? 1 : -Console.CursorLeft;
else Result := 2;
end
else
if char.IsHighSurrogate(c) then
Result := 0
else
case c of
char(7), char(8226): Result := 0;
char(8), char(9688): Result := (Console.CursorLeft = 0) ? 0 : -1;
char(9), char(9675):
begin
var NT: smallint := (Console.CursorLeft div 8 + 1) * 8;
if (NT < Console.BufferWidth) then
Result := NT - Console.CursorLeft
else
Result := Console.BufferWidth - Console.CursorLeft;
end;
char(10), char(9689): Result := Console.BufferWidth - Console.CursorLeft;
char(13), char(9834): Result := -Console.CursorLeft;
else Result := 1;
end;
end;
begin
var a := Arr(0);
var StopOnErr := true;
SCS(Console.LargestWindowWidth, 3);
var err := false;
var x, y: smallint;
var s: string;
for var i2 := 0 to a.Length - 1 do
for var i4 := 0 to a.Length - 1 do
begin
x := Console.CursorLeft;
y := Console.CursorTop;
s := char.ConvertFromUtf32(i2) + char.ConvertFromUtf32(i4);
x += CCL(s[1], false);
Write(s[1]);
for var i := 2 to s.Length do
begin
x += CCL(s[i], char.IsHighSurrogate(s[i - 1]));
Write(s[i]);
end;
y += x div Console.BufferWidth;
x := x mod Console.BufferWidth;
if (Console.CursorLeft <> x) or (Console.CursorTop <> y) then
begin
err := true;
WTF(Format('Err: xe = {0}, xb = {1}, ye = {2}, yb = {3}', x, Console.CursorLeft, y, Console.CursorTop));
end;
if char.IsHighSurrogate(s[s.Length]) then
Write(' ');
Console.Clear;
if err and StopOnErr then
break;
end;
if err then
Write('Ошибка!')
else
Write('Всё!');
while true do
begin
Console.Beep;
end;
end.
Тема: “юникодная консоль”.
Что изменится? Больше символов, вместо вопросительных знаков, или составные символы и суррогатные пары?
Где вы видели текстовые файлы в UTF-16? UTF-16 используется в вызовах Windows API и в файловой системе, а в файлах почти никогда не используется. В новых версиях Windows в консоли UTF-8 требуется по умолчанию.
К тому же в большинстве текстовых файлов не используется ничего кроме ASCII, а значит по умолчанию должна быть кодировка, которая при записи ASCII-символов их и пишет как есть. Из таких кодировок единственная, совместимая ещё и с юникодом — это UTF-8, так что выбора собственно и нет.
А она будет юникодной на основе UTF-16 или UTF-8? В новых версиях Windows примерно три года назад перешли на UTF-8 в консоли, но UTF-16 поддерживается для совместимости, хотя там недоступны новые возможности.
Как насчёт вывода в файл? Я предлагаю всё-таки сделать UTF-8 по умолчанию. А если нужен двоичный файл или требуется какая-то однобайтная кодировка вроде CP1251, то существуют нетипизированные файлы, которые просто file и file of byte / file of char.
Да, на Win10 с 2019 года. Но она далеко не у всех установлена, поэтому пока на это ориентироваться нельзя. “Внутри” PascalАВС.NET уже давно перешел на двухбайтную кодировку, но при работе с файлами в целях поддержки провозглашенной совместимости со старыми паскалями и Delphi нужна кодировка, позволяющая читать их старые файлы.
Внутренняя ошибка значит что произошла необработанная ошибка внутри компилятора, как тут. Это тоже всегда в issue.
Что касается решения - имя из наследника должно перекрывать унаследованное:
type
t1 = class
function f1(x: byte): word := 0;
end;
t2 = class(t1)
const f1 = 'abc';
end;
begin
var a := t2.f1;
a.GetType.ToString.Print;
end.
Ну а отчёт на самом деле мало что даёт. Он скорее для случаев когда ошибка воспроизводится только на вашей машине, но это редкость и я могу подтвердить что у меня так же.
Так и называется, минимальный код для воспроизведения.
И он таки нужен. В том 2-х строчном коде переименование работает. А в большом коде не понятно что именно стало причиной. Подозреваю что for
в комбинации с чем то ещё, но нужен минимальный код.
А это и 2 темы?
Я — про конфликты внутри IDE, а не свой код, но и это интересно.
Да, b
не переименовывается. Кстати, форматирование добавляет пробел в конце.
## for var a := 0 to 0 do
for var b := 0 to 0 do;
В принципе можно залить в issue IDE, но я сам в этом копаться не буду, потому что у разработчиков позиция вроде “ошибки которые не должны происходить - должны быть неудобными, чтоб их хотелось залить в issue” - непобедимая логика.
В смысле? Я привёл пример того же случая (функция из базового класса и константа с тем же именем в наследнике), но с пользовательским кодом. Потому что типы из библиотек, в том числе стандартных, должны работать так же как пользовательские типы.
Вот мне неудобно вручную собирать zip с отчётом и исходниками.
Про for
создать issue? Где?
Где наследники в случае issue?
UnicodeCategory
, как и все остальные перечисления, наследует от System.Enum
.
Переименование это фича IDE
, поэтому и в issue его. Хорошее общее правило - проблемы компилятора это то что можно получить не используя IDE, то есть с консольным компилятором. Включая компиляцией из проводника при тыке на файл:
Не знал.
Тогда я ошибся и заложил в название другой смысл. Название правильное?
Но вы ведь нашли что конфликт идёт с Enum.Format
. Откуда ему иначе взяться?
Та нет, вроде правильно. Хотя я бы назвал
Компилятор падает из за конфликта UnicodeCategory.Format и Enum.Format
Но это мой личный стиль, вы делайте как сами считайте правильным.
Именно поэтому и нужен UTF-8. В пределах ASCII он совместим со старыми кодировками, а что касается кириллицы, то в любом случае нужно заранее знать её кодировку (cp866, cp1251, utf-8), так как в TP и Delphi она разная. Переходить на запись в файл UTF-16 по умолчанию не следует. Так как в большинстве файлов, которые нужно читать из кода на паскале кириллицы не будет, а будет только ASCII (например списки чисел), то открывать файлы в UTF-8 по умолчанию вполне допустимо и желательно.
Вот с выводом в консоль — тут сложнее.
Исправили. Версия на сайте
Исправили. Версия на сайте
Ага, ага. Не будет. На ЕГЭ файлы, выгруженные из Word и Excel - они как раз с кириллицей.
То речь шла о совместимости с Turbo Pascal, то теперь Word и Excel… Ну там можно указать кодировку UTF-8 при экспорте, так что проблемы нет. В общем как я и говорил, для текстовых файлов какая-то другая кодировка по умолчанию не имеет смысла.