Замечания и предложения

Да. Ставьте скобки

Можете дать ответ поподробнее? Как я показал в примере кода - if-выражение работает внутри заголовка if-выражения и без скобок. И с ?: внутри заголовка ?:, конечно, тоже.

Это не очень интуитивно… И до меня дошло что можно попробовать скобки уже только когда начал все случаи тестировать. Надо хотя бы объясняющую ошибку. Особенно в случае s5 это странно выглядит.

А то вот в тут у меня изначально был случай s3. Пока не начал разбираться - я написал ?: внутри ?:, хотя если внешний тренарный оператор заменить на if - код выглядит значительно читабельнее.

Вообще то логично предположить, что работать должно и без скобок, потому что вот в этом примере выходит так, что код для s1 эквивалентен коду для s2, а значит выражение для ветки else в s1 считается полностью до точки с запятой. Cтранно, что для if...then...else с тернарником в else это не так.

var s1 := if false then 1 else 2 + 3;    // 5
  
var s2 := if false then 1 else (2 + 3);  // 5

var s3 := if true then 1 else 2 + 3;     // 1
  
var s4 := (if true then 1 else 2) + 3;   // 4

выражение для ветки else в s1 считается полностью до точки с запятой

Дело не в потоковом чтении, а в том что у if, как и у тренарников, приоритет ниже чем у всего остального (кроме скобок). Поэтому если скобок нет - if-выражение, как и ?: становится внешним узлом ещё на стадии синтаксиса.

Парсер недописали. Пользуйтесь скобками =).

Мы хотели со временем убирать ? :

Да, старые и новые if выражения не могут быть вложены друг в друга - это дестабилизирует грамматику. В грамматике действительно в новых if не может быть ? :

Если использовать только новые или только старые, то всё ОК.

Вообще, запишите в Issue - я попытаюсь вспомнить, почему в грамматике так сделано. Скорее всего потому что смешение приводит к конфликтам в грамматике, и тогда Issue я закрою. Но если нет, попробую исправить.

Значит ли это что вы хотите всё же заставить работать if-выражения в корне лямбды?

@Admin,Замените, пожалуйста, конструкцию вида

begin
  var a := 3;
  $'{a}'.Println;
end.

На

begin
  var a := 3;
  '${a}'.Println;
end.

Самое главное преимущество,это вложенность фигурных скобок. Сейчас,что бы вывести “{3}” Нужно писать много вложенных фигурных скобок,а с новой конструкцией это будет выглядеть так:

begin
  var a := 3;
  '{${a}}'.Println;
end.

Если не сложно.

Это специально, чтобы формат стал несовместим с C# ?

Вовсе нет,это для удобства.

Я использовал ReadlnReal в При пошаговом выполнении программы кнопки перехода на следующий шаг сереют и перестают быть активными. Почему сейчас при использовании появляется исключение (см. Помощь новичкам)?

Изучал http://pascalabc.net/wiki/index.php?title=События_event, решил выполнить код и произошло это:

image

Это падение компилятора. Точнее, скорее всего, PCUReader-а.
Надо найти минимальный код и запостить в issue.

Вообще я сейчас как раз делаю программу для автоматизации поиска минимального кода:


За стабильность пока не ручаюсь, но если вам и тут лень - можно сэкономить чуть чуть сил. И не ожидайте что программа сделает всё за вас. Я ещё даже нормальный парсер не прикрутил, поэтому убирать может только целыми строчками. То есть в конце придётся дочистить чтоб найти действительно минимальный код.

Чтоб использовать:

  1. Запустите PES.pas;

  2. Откройте папку в которой он лежит - в ней должно было создать папку Bucket;

  3. Положите в этот Bucket все файлы проекта (желательно без файлов вроде .pcu, .pdb и .exe) и снова запустите PES.pas;

  4. Вам должно показать какие ошибки выдаёт при компиляции и выполнении каждого из .pas файлов. Выберите ошибку для которой хотите минимальный код и ждите. Потом в папке Log найдёте результаты каждой стадии уменьшения исходников.

P.S. Считая что падает PCUReader - скорее всего придётся добавить ещё такую программу в проект:

procedure Compile(fname: string);
begin
  var psi := new System.Diagnostics.ProcessStartInfo('C:\Program Files (x86)\PascalABC.NET\pabcnetcclear.exe', fname);
  psi.UseShellExecute := false;
  psi.RedirectStandardOutput := true;
  psi.RedirectStandardError := true;
  var p := System.Diagnostics.Process.Start(psi);
  p.WaitForExit;
  p.StandardOutput.ReadToEnd.Println;
  p.StandardError.ReadToEnd.Println;
end;

begin
  loop 2 do Compile('ИмяИсходникаСОшибкой.pas');
end.

И в списке файлов при запуске PES выбрать запуск этой программы (он появится не сразу, а после того как PES выполнит её 1 раз).

Потому что чтоб читать .pcu - его надо сначала создать, то есть откомпилировать придётся 2 раза.

Предлагаю добавить подпрограммы округления до разрядов десятков, сотен, тысяч и т. д., например, так:

///Математическое округление до любого допустимого разряда.
function MR(value: real; digits: integer): real;
begin
  if (digits >= 0) then Result := System.Math.Round(value, digits, System.MidpointRounding.AwayFromZero)
  else Result := System.Math.Round(value / (10 ** -digits), System.MidpointRounding.AwayFromZero) * 10 ** -digits;
end;

///Математическое округление до BigInteger.
function MRBigInteger(value: real; digits: integer): BigInteger;
begin
  if (digits > 0) then raise new System.ArgumentOutOfRangeException('MR: digits>0')
  else if (digits = 0) then Result := TruncBigInteger(System.Math.Round(value, System.MidpointRounding.AwayFromZero))
  else Result := TruncBigInteger(System.Math.Round(value / (10 ** -digits), System.MidpointRounding.AwayFromZero) * 10 ** -digits);
end;

Округление до определённого порядка для real уже есть среди перегрузок Round.

А для создания такого BigInteger есть конструктор. Добавлять отдельную подпрограмму для new BigInteger(value * 10 ** n) - звучит очень странно.

Я не нашёл подпрограмму для округления целой части числа. Как это сделать, если это уже есть, или я неправильно понял?

Я нашёл только BigInteger.Create, который, опять же, не округляет целую часть числа, да ещё использует округление до ближайшего целого в меньшую сторону для положительных числел и в большую — для отрицательных.

А, понятно.
Только зачем вам это? Округление дробной части используется, к примеру, для вывода. Если делать округление для какой то математики - то уже и в определённой СС. Как то так:

function Round(x: real; digits, СС: integer): real;
begin
  var k := СС ** digits;
  Result := Round(x*k, 0) / k;
end;

begin
  Round(123.456, -1, 10).Println;
end.

Потому что округление это отдельная операция. new BigInteger скорее не округляет, а отбрасывается дробную часть числа.

##
Length('ABC').Print;
'ABC'.Length.Print;

@Admin как насчёт добавить ту Length, которая функция, в проверку здоровья кода? По моему в современном коде правильно использовать только .Length свойство. Но на куберфоруме Length(...) - один из самых встречающихся атавизмов, на ряду с глобальными переменными.

И давно вызов функции, одноименной со свойством, считается атавизмом?

Дело, в первую очередь, не в том что она одноимённая, а в том, что это глобальная подпрограмма, а не метод. Вызов по точке и выглядит чище, и в целом более современный.