From 5fec52615a291f0a7294dac4e1ebb796edcd729b Mon Sep 17 00:00:00 2001 From: Mikhalkovich Stanislav Date: Sat, 24 May 2025 21:36:36 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B0=D1=81=D0=BF=D0=B0=D0=BA=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D0=B0=20KeyValuePair|=20=D0=98=20=D0=B2=20foreach?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Configuration/GlobalAssemblyInfo.cs | 2 +- Configuration/Version.defs | 4 +- Release/pabcversion.txt | 2 +- ReleaseGenerators/PascalABCNET_version.nsh | 2 +- TestSuite/CompilationSamples/PABCSystem.pas | 143 ++++++++---------- TestSuite/CompilationSamples/School.pas | 2 +- TestSuite/CompilationSamples/graph3d.pas | 2 +- .../SyntaxTreeVisitorNodes/Foreach.cs | 14 +- .../semantic_checks_for_sugar.cs | 26 +++- .../TreeConversion/syntax_tree_visitor.cs | 41 +++-- bin/Lib/Graph3D.pas | 2 +- bin/Lib/PABCSystem.pas | 126 ++++++--------- bin/Lib/School.pas | 2 +- bin/Lng/Eng/SemanticErrors_ms.dat | 3 +- bin/Lng/Rus/SemanticErrors_ms.dat | 7 +- 15 files changed, 186 insertions(+), 192 deletions(-) diff --git a/Configuration/GlobalAssemblyInfo.cs b/Configuration/GlobalAssemblyInfo.cs index e71b73edc..ef90c54d2 100644 --- a/Configuration/GlobalAssemblyInfo.cs +++ b/Configuration/GlobalAssemblyInfo.cs @@ -15,7 +15,7 @@ internal static class RevisionClass public const string Major = "3"; public const string Minor = "10"; public const string Build = "3"; - public const string Revision = "3627"; + public const string Revision = "3632"; public const string MainVersion = Major + "." + Minor; public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision; diff --git a/Configuration/Version.defs b/Configuration/Version.defs index 359b742e2..06f548182 100644 --- a/Configuration/Version.defs +++ b/Configuration/Version.defs @@ -1,4 +1,4 @@ -%MINOR%=10 -%REVISION%=3627 %COREVERSION%=3 +%REVISION%=3632 +%MINOR%=10 %MAJOR%=3 diff --git a/Release/pabcversion.txt b/Release/pabcversion.txt index 5bc2b1dca..ffb01753a 100644 --- a/Release/pabcversion.txt +++ b/Release/pabcversion.txt @@ -1 +1 @@ -3.10.3.3627 +3.10.3.3632 diff --git a/ReleaseGenerators/PascalABCNET_version.nsh b/ReleaseGenerators/PascalABCNET_version.nsh index 3f4347ff8..0dea5cbfd 100644 --- a/ReleaseGenerators/PascalABCNET_version.nsh +++ b/ReleaseGenerators/PascalABCNET_version.nsh @@ -1 +1 @@ -!define VERSION '3.10.3.3627' +!define VERSION '3.10.3.3632' diff --git a/TestSuite/CompilationSamples/PABCSystem.pas b/TestSuite/CompilationSamples/PABCSystem.pas index 1eeb615f3..f0213cba7 100644 --- a/TestSuite/CompilationSamples/PABCSystem.pas +++ b/TestSuite/CompilationSamples/PABCSystem.pas @@ -2334,8 +2334,10 @@ function Pred(x: uint64): uint64; ///-- function Pred(x: boolean): boolean; -/// Возвращает True, если значение val находится между a и b включительно (a ≤ val ≤ b) +/// Возвращает True, если значение val находится между a и b включительно function InRange(val, a, b: T): boolean; where T: IComparable; +/// Возвращает True, если значение val находится между a и b (включительно) независимо от порядка a и b +function Between(val, a, b: T): boolean; where T: IComparable; /// Меняет местами значения двух переменных procedure Swap(var a, b: T); /// Возвращает True, если достигнут конец строки @@ -3166,43 +3168,44 @@ var const WRITELN_IN_BINARYFILE_ERROR_MESSAGE = 'Операция Writeln не применима к бинарным файлам!!Writeln is not applicable to binary files'; InternalNullBasedArrayName = 'NullBasedArray'; - FILE_NOT_ASSIGNED = 'Для файловой переменной не вызвана процедура Assign!!File is not assigned'; - FILE_NOT_OPENED = 'Файл не открыт!!File is not opened'; - FILE_NOT_OPENED_FOR_READING = 'Файл не открыт на чтение!!File is not opened for reading'; - FILE_NOT_OPENED_FOR_WRITING = 'Файл не открыт на запись!!File is not opened for writing'; - READ_LEXEM_AFTER_END_OF_TEXT_FILE = 'Попытка считывания за концом текстового файла!!Read after end of text file'; - READ_LEXEM_AFTER_END_OF_INPUT_STREAM = 'Попытка считывания за концом потока ввода!!Read after end of input stream'; - RANGE_ERROR_MESSAGE = 'Выход за границы диапазона!!Out of range'; - EOF_FOR_TEXT_WRITEOPENED = 'Функция Eof не может быть вызвана для текстового файла, открытого на запись!!Eof function can''t be called for file, opened on writing'; - EOLN_FOR_TEXT_WRITEOPENED = 'Функция Eoln не может быть вызвана для текстового файла, открытого на запись!!Eoln function can''t be called for file, opened on writing'; - SEEKEOF_FOR_TEXT_WRITEOPENED = 'Функция SeekEof не может быть вызвана для текстового файла, открытого на запись!!SeekEof function can''t be called for file, opened on writing'; - SEEKEOLN_FOR_TEXT_WRITEOPENED = 'Функция SeekEoln не может быть вызвана для текстового файла, открытого на запись!!SeekEoln function can''t be called for file, opened on writing'; - BAD_TYPE_IN_RUNTIMESIZEOF = 'Для типизированных файлов нельзя указывать тип элементов, являющийся ссылочным или содержащий ссылочные поля!!Bad Type in RunTimeSizeOf'; + FILE_NOT_ASSIGNED = 'Для файловой переменной не вызвана процедура Assign!!File variable was not assigned using Assign'; + FILE_NOT_OPENED = 'Файл не открыт!!File is not open'; + FILE_NOT_OPENED_FOR_READING = 'Файл не открыт на чтение!!File is not open for reading'; + FILE_NOT_OPENED_FOR_WRITING = 'Файл не открыт на запись!!File is not open for writing'; + READ_LEXEM_AFTER_END_OF_TEXT_FILE = 'Попытка считывания за концом текстового файла!!Attempt to read beyond end of text file'; + READ_LEXEM_AFTER_END_OF_INPUT_STREAM = 'Попытка считывания за концом потока ввода!!Attempt to read beyond end of input stream'; + RANGE_ERROR_MESSAGE = 'Выход за пределы допустимого диапазона!!Out of range'; + EOF_FOR_TEXT_WRITEOPENED = 'Функция Eof не может быть вызвана для текстового файла, открытого на запись!!Eof function cannot be called on a text file opened for writing'; + EOLN_FOR_TEXT_WRITEOPENED = 'Функция Eoln не может быть вызвана для текстового файла, открытого на запись!!Eoln function cannot be called on a text file opened for writing'; + SEEKEOF_FOR_TEXT_WRITEOPENED = 'Функция SeekEof не может быть вызвана для текстового файла, открытого на запись!!SeekEof function cannot be called on a text file opened for writing'; + SEEKEOLN_FOR_TEXT_WRITEOPENED = 'Функция SeekEoln не может быть вызвана для текстового файла, открытого на запись!!SeekEoln function cannot be called on a text file opened for writing'; + BAD_TYPE_IN_RUNTIMESIZEOF = 'Типизированный файл не может содержать ссылочный тип или тип со ссылочными полями!!Typed file cannot contain a reference type or a type with reference fields'; PARAMETER_MUST_BE_GREATER_EQUAL_0 = 'Параметр должен быть >= 0!!Parameter must be >= 0'; - PARAMETER_MUST_BE_GREATER_0 = 'Параметр должен быть > 0!!Parameter must be > 0'; - PARAMETER_MUST_BE_GREATER_1 = 'Параметр должен быть > 1!!Parameter must be > 1'; - PARAMETER_STEP_MUST_BE_NOT_EQUAL_0 = 'Параметр step не может быть равен 0!!The step parameter must be not equal to 0'; - PARAMETER_STEP_MUST_BE_GREATER_0 = 'Параметр step должен быть > 0!!The step parameter must be not greater than 0'; - PARAMETER_FROM_OUT_OF_RANGE = 'Параметр from за пределами диапазона!!The from parameter out of bounds'; - PARAMETER_TO_OUT_OF_RANGE = 'Параметр to за пределами диапазона!!The to parameter out of bounds'; - ARR_LENGTH_MUST_BE_MATCH_TO_MATR_SIZE = 'Размер одномерного массива не согласован с размером двумерного массива!!The 1-dim array length does not match 2-dim array size'; - INITELEM_COUNT_MUST_BE_EQUAL_TO_MATRIX_ELEMS_COUNT = 'Количество инициализирующих элементов не совпадает с количеством элементов матрицы!!The number of elements in init list must be equal to the number of elements in matrix'; - TYPED_FILE_CANBE_OPENED_IN_SINGLEBYTE_ENCODING_ONLY = 'При открытии типизированного файла можно указывать только однобайтную кодировку!!Typed file can be opened in single byte encoding only'; - BAD_ROW_INDEX = 'Один из элементов массива RowIndex выходит за пределы индексов строк двумерного массива!!One of the elements of RowIndex array is out of range of 2-dim array row indexes'; - BAD_COL_INDEX = 'Один из элементов массива ColIndex выходит за пределы индексов столбцов двумерного массива!!One of the elements of ColIndex array is out of range of 2-dim array column indexes'; - BAD_ROW_INDEX_FROM = 'FromRow выходит за пределы индексов строк двумерного массива!!FromRow is out of range of 2-dim array row indexes'; - BAD_ROW_INDEX_TO = 'ToRow выходит за пределы индексов строк двумерного массива!!ToRow is out of range of 2-dim array row indexes'; - BAD_COL_INDEX_FROM = 'FromCol выходит за пределы индексов строк двумерного массива!!FromCol is out of range of 2-dim array column indexes'; - BAD_COL_INDEX_TO = 'ToCol выходит за пределы индексов строк двумерного массива!!ToCol is out of range of 2-dim array column indexes'; - SLICE_SIZE_AND_RIGHT_VALUE_SIZE_MUST_BE_EQUAL = 'Размеры среза и присваиваемого выражения должны быть равны!!Slice size and assigned expression size must be equal'; + PARAMETER_MUST_BE_GREATER_0 = 'Параметр должен быть больше 0!!Parameter must be > 0'; + PARAMETER_MUST_BE_GREATER_1 = 'Параметр должен быть больше 1!!Parameter must be > 1'; + PARAMETER_STEP_MUST_BE_NOT_EQUAL_0 = 'Параметр step не может быть равен 0!!Step parameter must not be equal to 0'; + PARAMETER_STEP_MUST_BE_GREATER_0 = 'Параметр step должен быть > 0!!Step parameter must be greater than 0'; + PARAMETER_FROM_OUT_OF_RANGE = 'Параметр from за пределами диапазона!!From parameter is out of range'; + PARAMETER_TO_OUT_OF_RANGE = 'Параметр to за пределами диапазона!!To parameter is out of range'; + ARR_LENGTH_MUST_BE_MATCH_TO_MATR_SIZE = 'Размер одномерного массива не согласован с размером двумерного массива!!The length of the 1D array must match the size of the 2D array'; + INITELEM_COUNT_MUST_BE_EQUAL_TO_MATRIX_ELEMS_COUNT = 'Количество инициализирующих элементов не совпадает с количеством элементов матрицы!!The number of initializer elements must equal the number of elements in the matrix'; + TYPED_FILE_CANBE_OPENED_IN_SINGLEBYTE_ENCODING_ONLY = 'При открытии типизированного файла можно указывать только однобайтную кодировку!!Typed files can only be opened with single-byte encodings'; + BAD_ROW_INDEX = 'Один из элементов массива RowIndex выходит за пределы индексов строк двумерного массива!!An element in the RowIndex array is out of range for the matrix row indices'; + BAD_COL_INDEX = 'Один из элементов массива ColIndex выходит за пределы индексов столбцов двумерного массива!!An element in the ColIndex array is out of range for the matrix column indices'; + BAD_ROW_INDEX_FROM = 'FromRow выходит за пределы индексов строк двумерного массива!!FromRow is out of range for the matrix row indices'; + BAD_ROW_INDEX_TO = 'ToRow выходит за пределы индексов строк двумерного массива!!ToRow is out of range for the matrix row indices'; + BAD_COL_INDEX_FROM = 'FromCol выходит за пределы индексов строк двумерного массива!!FromCol is out of range for the matrix column indices'; + BAD_COL_INDEX_TO = 'ToCol выходит за пределы индексов строк двумерного массива!!ToCol is out of range for the matrix column indices'; + SLICE_SIZE_AND_RIGHT_VALUE_SIZE_MUST_BE_EQUAL = 'Размеры среза и присваиваемого выражения должны быть равны!!Slice size must match the size of the assigned expression'; MATR_DIMENSIONS_MUST_BE_EQUAL = 'Размеры матриц должны совпадать!!Matrix dimensions must be equal'; - COUNT_PARAMS_MAXFUN_MUSTBE_GREATER1 = 'Количество параметров функции Max должно быть > 1!!The number of parameters of the Max function must be > 1'; - COUNT_PARAMS_MINFUN_MUSTBE_GREATER1 = 'Количество параметров функции Min должно быть > 1!!The number of parameters of the Min function must be > 1'; - Format_InvalidString = 'Входная строка имела неверный формат!!Input string was not in a correct format'; + COUNT_PARAMS_MAXFUN_MUSTBE_GREATER1 = 'Количество параметров функции Max должно быть > 1!!Max function must have more than one parameter'; + COUNT_PARAMS_MINFUN_MUSTBE_GREATER1 = 'Количество параметров функции Min должно быть > 1!!Min function must have more than one parameter'; + Format_InvalidString = 'Входная строка имела неверный формат!!Input string was not in a valid format'; Overflow_Int32 = 'Целочисленное переполнение!!Integer overflow'; - FOR_STEP_CANNOT_BE_EQUAL0 = 'Шаг цикла for не может быт равен 0!!Step of the for loop cannot be equal to 0'; + FOR_STEP_CANNOT_BE_EQUAL0 = 'Шаг цикла for не может быт равен 0!!The step of a for loop cannot be 0'; SEQUENCE_CANNOT_BE_EMPTY = 'Последовательность не может быть пустой!!Sequence cannot be empty'; ARRAY_CANNOT_BE_EMPTY = 'Массив не может быть пустым!!Array cannot be empty'; + MIN_CANNOT_BE_GREATER_THAN_MAX = 'CLamp: min не может быть больше чем max!!CLamp: min cannot be greater than max'; // ----------------------------------------------------- // WINAPI // ----------------------------------------------------- @@ -10684,12 +10687,21 @@ begin Result := char(integer(x)-n); end; -/// Возвращает True, если значение val находится между a и b включительно (a ≤ val ≤ b) +/// Возвращает True, если значение val находится между a и b включительно function InRange(val, a, b: T): boolean; where T: IComparable; begin Result := (val.CompareTo(a) >= 0) and (val.CompareTo(b) <= 0); end; +/// Возвращает True, если значение val находится между a и b (включительно) независимо от порядка a и b +function Between(val, a, b: T): boolean; where T: IComparable; +begin + if a.CompareTo(b) > 0 then + Result := (val.CompareTo(b) >= 0) and (val.CompareTo(a) <= 0) + else + Result := (val.CompareTo(a) >= 0) and (val.CompareTo(b) <= 0); +end; + procedure Swap(var a, b: T); begin var v := a; @@ -14267,29 +14279,15 @@ begin Result := Range(0, Self - 1); end; -/// Возвращает число, ограниченное диапазоном от bottom до top включительно -function Clamp(Self: integer; bottom,top: integer): integer; extensionmethod; +/// Возвращает число, ограниченное диапазоном от min до max включительно +function Clamp(Self: integer; min,max: integer): integer; extensionmethod; begin - if Self < bottom then - Result := bottom - else if Self > top then - Result := top - else Result := Self; -end; - -/// Возвращает число, ограниченное величиной top сверху -function ClampTop(Self: integer; top: integer): integer; extensionmethod; -begin - if Self > top then - Result := top - else Result := Self; -end; - -/// Возвращает число, ограниченное величиной bottom снизу -function ClampBottom(Self: integer; bottom: integer): integer; extensionmethod; -begin - if Self < bottom then - Result := bottom + if min > max then + raise new System.ArgumentException(GetTranslation(MIN_CANNOT_BE_GREATER_THAN_MAX)); + if Self < min then + Result := min + else if Self > max then + Result := max else Result := Self; end; @@ -14384,33 +14382,18 @@ begin Result := Format('{0:f' + frac + '}', Self) end; -/// Возвращает число, ограниченное диапазоном от bottom до top включительно -function Clamp(Self: real; bottom,top: real): real; extensionmethod; +/// Возвращает число, ограниченное диапазоном от min до max включительно +function Clamp(Self: real; min,max: real): real; extensionmethod; begin - if Self < bottom then - Result := bottom - else if Self > top then - Result := top + if min > max then + raise new System.ArgumentException(GetTranslation(MIN_CANNOT_BE_GREATER_THAN_MAX)); + if Self < min then + Result := min + else if Self > max then + Result := max else Result := Self; end; -/// Возвращает число, ограниченное величиной top сверху -function ClampTop(Self: real; top: real): real; extensionmethod; -begin - if Self > top then - Result := top - else Result := Self; -end; - -/// Возвращает число, ограниченное величиной bottom снизу -function ClampBottom(Self: real; bottom: real): real; extensionmethod; -begin - if Self < bottom then - Result := bottom - else Result := Self; -end; - - //------------------------------------------------------------------------------ //>> Методы расширения типа char # Extension methods for char //------------------------------------------------------------------------------ @@ -14487,7 +14470,7 @@ begin Result := Self.Split(|oldStr|, count+1, System.StringSplitOptions.None).JoinToString(newStr); end; -/// Возвращает True если значение находится между двумя другими +/// Возвращает True если строка находится между двумя другими (лексикографическое сравнение) function Between(Self: string; a, b: string): boolean; extensionmethod; begin Result := (a <= Self) and (Self <= b) or (b <= Self) and (Self <= a); diff --git a/TestSuite/CompilationSamples/School.pas b/TestSuite/CompilationSamples/School.pas index 68e10fc62..e404da46d 100644 --- a/TestSuite/CompilationSamples/School.pas +++ b/TestSuite/CompilationSamples/School.pas @@ -827,7 +827,7 @@ end; /// Первые k простых чисел function FirstPrimes(k: integer): List; begin - k := k.ClampTop(integer.MaxValue); // на всякий случай + // k := Min(k,integer.MaxValue); // на всякий случай if k <= nPrimeDivs then Result := LPrimes[:k] else begin diff --git a/TestSuite/CompilationSamples/graph3d.pas b/TestSuite/CompilationSamples/graph3d.pas index 3e46b57bb..b097a675b 100644 --- a/TestSuite/CompilationSamples/graph3d.pas +++ b/TestSuite/CompilationSamples/graph3d.pas @@ -4263,7 +4263,7 @@ function BillboardText(p: Point3D; Text: string; Fontsize: real) := BillboardTex function CoordinateSystem(ArrowsLength, Diameter: real): CoordinateSystemT := Inv(()->CoordinateSystemT.Create(0, 0, 0, arrowslength, diameter)); -function CoordinateSystem(ArrowsLength: real) := CoordinateSystem(arrowslength, (arrowslength / 10).ClampTop(0.18)); +function CoordinateSystem(ArrowsLength: real) := CoordinateSystem(arrowslength, Min(arrowslength / 10, 0.18)); function Text3D(x, y, z: real; Text: string; Height: real; fontname: string; c: Color): TextT := Inv(()->TextT.Create(x, y, z, text, height, fontname, c)); diff --git a/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Foreach.cs b/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Foreach.cs index a8f25cd54..b0f31744b 100644 --- a/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Foreach.cs +++ b/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Foreach.cs @@ -4,6 +4,7 @@ using PascalABCCompiler.TreeRealization; using TreeConverter.LambdaExpressions; using System.Linq; using for_node = PascalABCCompiler.SyntaxTree.for_node; +using System.Collections.Generic; namespace PascalABCCompiler.TreeConverter { @@ -108,9 +109,10 @@ namespace PascalABCCompiler.TreeConverter var IsTuple = IsTupleType(t); - var IsSequence = !IsTuple && IsSequenceType(t); + var IsKeyValuePair = !IsTuple && IsKeyValuePairType(t); + var IsSequence = !IsTuple && !IsKeyValuePair && IsSequenceType(t); - if (!IsTuple && !IsSequence) + if (!IsTuple && !IsSequence && !IsKeyValuePair) { AddError(inwhatloc, "TUPLE_OR_SEQUENCE_EXPECTED_FOREACH"); } @@ -119,7 +121,13 @@ namespace PascalABCCompiler.TreeConverter { var n = vars.idents.Count(); if (n > t.GetGenericArguments().Count()) - AddError(get_location(vars), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMRNT"); + AddError(get_location(vars), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT"); + } + if (IsKeyValuePair) + { + var n = vars.idents.Count(); + if (n > 2) + AddError(get_location(vars), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_KEYVALUEPAIR_ASSIGNMENT"); } } diff --git a/TreeConverter/TreeConversion/semantic_checks_for_sugar.cs b/TreeConverter/TreeConversion/semantic_checks_for_sugar.cs index a6b188094..31752179e 100644 --- a/TreeConverter/TreeConversion/semantic_checks_for_sugar.cs +++ b/TreeConverter/TreeConversion/semantic_checks_for_sugar.cs @@ -21,9 +21,10 @@ namespace PascalABCCompiler.TreeConverter AddError(expr.location, "TUPLE_OR_SEQUENCE_EXPECTED"); var IsTuple = IsTupleType(t); + var IsKeyValuePair = !IsTuple && IsKeyValuePairType(t); var IsSequence = !IsTuple && IsSequenceType(t); - if (!IsTuple && !IsSequence) + if (!IsTuple && !IsKeyValuePair && !IsSequence) { AddError(expr.location, "TUPLE_OR_SEQUENCE_EXPECTED"); } @@ -32,7 +33,13 @@ namespace PascalABCCompiler.TreeConverter { var n = vars.variables.Count(); if (n > t.GetGenericArguments().Count()) - AddError(get_location(vars), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMRNT"); + AddError(get_location(vars), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT"); + } + if (IsKeyValuePair) + { + var n = vars.variables.Count(); + if (n > 2) + AddError(get_location(vars), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_KEYVALUEPAIR_ASSIGNMENT"); } } @@ -52,12 +59,13 @@ namespace PascalABCCompiler.TreeConverter AddError(expr.location, "TUPLE_OR_SEQUENCE_EXPECTED"); return; } - + var IsTuple = IsTupleType(t); - var IsSequence = !IsTuple && IsSequenceType(t); + var IsKeyValuePair = !IsTuple && IsKeyValuePairType(t); + var IsSequence = !IsTuple && !IsKeyValuePair && IsSequenceType(t); - if (!IsTuple && !IsSequence) + if (!IsTuple && !IsKeyValuePair && !IsSequence) { AddError(expr.location, "TUPLE_OR_SEQUENCE_EXPECTED"); } @@ -66,7 +74,13 @@ namespace PascalABCCompiler.TreeConverter { var n = vars.idents.Count(); if (n > t.GetGenericArguments().Count()) - AddError(get_location(vars), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMRNT"); + AddError(get_location(vars), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT"); + } + if (IsKeyValuePair) + { + var n = vars.idents.Count(); + if (n > 2) + AddError(get_location(vars), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_KEYVALUEPAIR_ASSIGNMENT"); } } diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index 048323ad6..837d980aa 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -19004,9 +19004,9 @@ namespace PascalABCCompiler.TreeConverter // выбираем IEnumerable if (genericInterfaceCount == 1) return filteredInterfaces.First(item => item.is_generic_type_instance); - // явно реализует IEnumerable + // явно реализует IEnumerable - странно - заменил на null - SSM 23.05.25 else - return IEnumType; + return null; // IEnumType; case 1: var method = methods[0]; @@ -22183,12 +22183,17 @@ namespace PascalABCCompiler.TreeConverter return !t.IsArray && (t.FullName.StartsWith("System.Tuple") || t.FullName.StartsWith("System.ValueTuple")); } + public bool IsKeyValuePairType(Type t) + { + return t.FullName.StartsWith("System.Collections.Generic.KeyValuePair`2"); + } + public bool IsSequenceType(Type t) { return t.Name.Equals("IEnumerable`1") || t.GetInterface("IEnumerable`1") != null; } - private void CheckUnpacking(expression ex, out expression_node sem_ex, out bool IsTuple, out bool IsSequence, int countvars, syntax_tree_node stn) + /*private void CheckUnpacking(expression ex, out expression_node sem_ex, out bool IsTuple, out bool IsSequence, int countvars, syntax_tree_node stn) { sem_ex = convert_strong(ex); sem_ex = convert_if_typed_expression_to_function_call(sem_ex); @@ -22206,7 +22211,7 @@ namespace PascalABCCompiler.TreeConverter if (IsTuple) { if (countvars > t.GetGenericArguments().Count()) - AddError(get_location(stn), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMRNT"); + AddError(get_location(stn), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT"); } } @@ -22223,7 +22228,7 @@ namespace PascalABCCompiler.TreeConverter dn = new method_call(dn, pars); } return dn; - } + }*/ public override void visit(SyntaxTree.assign_tuple asstup) // сахарный узел { @@ -22286,7 +22291,7 @@ namespace PascalABCCompiler.TreeConverter { var nn = assvartup.idents.idents.Count(); if (nn > t.GetGenericArguments().Count()) - AddError(get_location(assvartup.idents), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMRNT"); + AddError(get_location(assvartup.idents), "TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT"); }*/ @@ -22331,6 +22336,7 @@ namespace PascalABCCompiler.TreeConverter { var IsSequence = false; var IsTuple = false; + var IsKeyValuePair = false; var sem_ex = convert_strong(ith.id); sem_ex = convert_if_typed_expression_to_function_call(sem_ex); var t = ConvertSemanticTypeNodeToNETType(sem_ex.type); @@ -22340,19 +22346,22 @@ namespace PascalABCCompiler.TreeConverter type_node elem_type = null; var b = FindIEnumerableElementType(sem_ex.type, ref elem_type, out bb); if (b) + // Не очень понятно, зачем это нужно. И это точно не срабатывает IsSequence = true; else AddError(sem_ex.location, "TUPLE_OR_SEQUENCE_EXPECTED"); - } - + if (t != null) IsTuple = IsTupleType(t); - - if (t != null) - IsSequence = !IsTuple && IsSequenceType(t); - if (!IsTuple && !IsSequence) + if (t != null) + IsKeyValuePair = !IsTuple && IsKeyValuePairType(t); + + if (t != null) + IsSequence = !IsTuple && !IsKeyValuePair && IsSequenceType(t); + + if (!IsTuple && !IsSequence && !IsKeyValuePair) { AddError(sem_ex.location, "TUPLE_OR_SEQUENCE_EXPECTED"); } @@ -22373,9 +22382,15 @@ namespace PascalABCCompiler.TreeConverter ReplaceUsingParent(ith, mc); visit(mc); } + else if (IsKeyValuePair) + { + var meth_name = i == 0 ? "Key" : "Value"; + var dn = new dot_node(ith.id.TypedClone(), new ident(meth_name)); + ReplaceUsingParent(ith, dn); + visit(dn); + } } - public override void visit(var_tuple_def_statement vtd) { AddError(get_location(vtd), "SUGARED_NODE_{0}_IN_SYNTAX_TREE_VISITOR", vtd.GetType().Name); diff --git a/bin/Lib/Graph3D.pas b/bin/Lib/Graph3D.pas index 3e46b57bb..b097a675b 100644 --- a/bin/Lib/Graph3D.pas +++ b/bin/Lib/Graph3D.pas @@ -4263,7 +4263,7 @@ function BillboardText(p: Point3D; Text: string; Fontsize: real) := BillboardTex function CoordinateSystem(ArrowsLength, Diameter: real): CoordinateSystemT := Inv(()->CoordinateSystemT.Create(0, 0, 0, arrowslength, diameter)); -function CoordinateSystem(ArrowsLength: real) := CoordinateSystem(arrowslength, (arrowslength / 10).ClampTop(0.18)); +function CoordinateSystem(ArrowsLength: real) := CoordinateSystem(arrowslength, Min(arrowslength / 10, 0.18)); function Text3D(x, y, z: real; Text: string; Height: real; fontname: string; c: Color): TextT := Inv(()->TextT.Create(x, y, z, text, height, fontname, c)); diff --git a/bin/Lib/PABCSystem.pas b/bin/Lib/PABCSystem.pas index a1a5cd7cb..f0213cba7 100644 --- a/bin/Lib/PABCSystem.pas +++ b/bin/Lib/PABCSystem.pas @@ -3168,43 +3168,44 @@ var const WRITELN_IN_BINARYFILE_ERROR_MESSAGE = 'Операция Writeln не применима к бинарным файлам!!Writeln is not applicable to binary files'; InternalNullBasedArrayName = 'NullBasedArray'; - FILE_NOT_ASSIGNED = 'Для файловой переменной не вызвана процедура Assign!!File is not assigned'; - FILE_NOT_OPENED = 'Файл не открыт!!File is not opened'; - FILE_NOT_OPENED_FOR_READING = 'Файл не открыт на чтение!!File is not opened for reading'; - FILE_NOT_OPENED_FOR_WRITING = 'Файл не открыт на запись!!File is not opened for writing'; - READ_LEXEM_AFTER_END_OF_TEXT_FILE = 'Попытка считывания за концом текстового файла!!Read after end of text file'; - READ_LEXEM_AFTER_END_OF_INPUT_STREAM = 'Попытка считывания за концом потока ввода!!Read after end of input stream'; - RANGE_ERROR_MESSAGE = 'Выход за границы диапазона!!Out of range'; - EOF_FOR_TEXT_WRITEOPENED = 'Функция Eof не может быть вызвана для текстового файла, открытого на запись!!Eof function can''t be called for file, opened on writing'; - EOLN_FOR_TEXT_WRITEOPENED = 'Функция Eoln не может быть вызвана для текстового файла, открытого на запись!!Eoln function can''t be called for file, opened on writing'; - SEEKEOF_FOR_TEXT_WRITEOPENED = 'Функция SeekEof не может быть вызвана для текстового файла, открытого на запись!!SeekEof function can''t be called for file, opened on writing'; - SEEKEOLN_FOR_TEXT_WRITEOPENED = 'Функция SeekEoln не может быть вызвана для текстового файла, открытого на запись!!SeekEoln function can''t be called for file, opened on writing'; - BAD_TYPE_IN_RUNTIMESIZEOF = 'Для типизированных файлов нельзя указывать тип элементов, являющийся ссылочным или содержащий ссылочные поля!!Bad Type in RunTimeSizeOf'; + FILE_NOT_ASSIGNED = 'Для файловой переменной не вызвана процедура Assign!!File variable was not assigned using Assign'; + FILE_NOT_OPENED = 'Файл не открыт!!File is not open'; + FILE_NOT_OPENED_FOR_READING = 'Файл не открыт на чтение!!File is not open for reading'; + FILE_NOT_OPENED_FOR_WRITING = 'Файл не открыт на запись!!File is not open for writing'; + READ_LEXEM_AFTER_END_OF_TEXT_FILE = 'Попытка считывания за концом текстового файла!!Attempt to read beyond end of text file'; + READ_LEXEM_AFTER_END_OF_INPUT_STREAM = 'Попытка считывания за концом потока ввода!!Attempt to read beyond end of input stream'; + RANGE_ERROR_MESSAGE = 'Выход за пределы допустимого диапазона!!Out of range'; + EOF_FOR_TEXT_WRITEOPENED = 'Функция Eof не может быть вызвана для текстового файла, открытого на запись!!Eof function cannot be called on a text file opened for writing'; + EOLN_FOR_TEXT_WRITEOPENED = 'Функция Eoln не может быть вызвана для текстового файла, открытого на запись!!Eoln function cannot be called on a text file opened for writing'; + SEEKEOF_FOR_TEXT_WRITEOPENED = 'Функция SeekEof не может быть вызвана для текстового файла, открытого на запись!!SeekEof function cannot be called on a text file opened for writing'; + SEEKEOLN_FOR_TEXT_WRITEOPENED = 'Функция SeekEoln не может быть вызвана для текстового файла, открытого на запись!!SeekEoln function cannot be called on a text file opened for writing'; + BAD_TYPE_IN_RUNTIMESIZEOF = 'Типизированный файл не может содержать ссылочный тип или тип со ссылочными полями!!Typed file cannot contain a reference type or a type with reference fields'; PARAMETER_MUST_BE_GREATER_EQUAL_0 = 'Параметр должен быть >= 0!!Parameter must be >= 0'; - PARAMETER_MUST_BE_GREATER_0 = 'Параметр должен быть > 0!!Parameter must be > 0'; - PARAMETER_MUST_BE_GREATER_1 = 'Параметр должен быть > 1!!Parameter must be > 1'; - PARAMETER_STEP_MUST_BE_NOT_EQUAL_0 = 'Параметр step не может быть равен 0!!The step parameter must be not equal to 0'; - PARAMETER_STEP_MUST_BE_GREATER_0 = 'Параметр step должен быть > 0!!The step parameter must be not greater than 0'; - PARAMETER_FROM_OUT_OF_RANGE = 'Параметр from за пределами диапазона!!The from parameter out of bounds'; - PARAMETER_TO_OUT_OF_RANGE = 'Параметр to за пределами диапазона!!The to parameter out of bounds'; - ARR_LENGTH_MUST_BE_MATCH_TO_MATR_SIZE = 'Размер одномерного массива не согласован с размером двумерного массива!!The 1-dim array length does not match 2-dim array size'; - INITELEM_COUNT_MUST_BE_EQUAL_TO_MATRIX_ELEMS_COUNT = 'Количество инициализирующих элементов не совпадает с количеством элементов матрицы!!The number of elements in init list must be equal to the number of elements in matrix'; - TYPED_FILE_CANBE_OPENED_IN_SINGLEBYTE_ENCODING_ONLY = 'При открытии типизированного файла можно указывать только однобайтную кодировку!!Typed file can be opened in single byte encoding only'; - BAD_ROW_INDEX = 'Один из элементов массива RowIndex выходит за пределы индексов строк двумерного массива!!One of the elements of RowIndex array is out of range of 2-dim array row indexes'; - BAD_COL_INDEX = 'Один из элементов массива ColIndex выходит за пределы индексов столбцов двумерного массива!!One of the elements of ColIndex array is out of range of 2-dim array column indexes'; - BAD_ROW_INDEX_FROM = 'FromRow выходит за пределы индексов строк двумерного массива!!FromRow is out of range of 2-dim array row indexes'; - BAD_ROW_INDEX_TO = 'ToRow выходит за пределы индексов строк двумерного массива!!ToRow is out of range of 2-dim array row indexes'; - BAD_COL_INDEX_FROM = 'FromCol выходит за пределы индексов строк двумерного массива!!FromCol is out of range of 2-dim array column indexes'; - BAD_COL_INDEX_TO = 'ToCol выходит за пределы индексов строк двумерного массива!!ToCol is out of range of 2-dim array column indexes'; - SLICE_SIZE_AND_RIGHT_VALUE_SIZE_MUST_BE_EQUAL = 'Размеры среза и присваиваемого выражения должны быть равны!!Slice size and assigned expression size must be equal'; + PARAMETER_MUST_BE_GREATER_0 = 'Параметр должен быть больше 0!!Parameter must be > 0'; + PARAMETER_MUST_BE_GREATER_1 = 'Параметр должен быть больше 1!!Parameter must be > 1'; + PARAMETER_STEP_MUST_BE_NOT_EQUAL_0 = 'Параметр step не может быть равен 0!!Step parameter must not be equal to 0'; + PARAMETER_STEP_MUST_BE_GREATER_0 = 'Параметр step должен быть > 0!!Step parameter must be greater than 0'; + PARAMETER_FROM_OUT_OF_RANGE = 'Параметр from за пределами диапазона!!From parameter is out of range'; + PARAMETER_TO_OUT_OF_RANGE = 'Параметр to за пределами диапазона!!To parameter is out of range'; + ARR_LENGTH_MUST_BE_MATCH_TO_MATR_SIZE = 'Размер одномерного массива не согласован с размером двумерного массива!!The length of the 1D array must match the size of the 2D array'; + INITELEM_COUNT_MUST_BE_EQUAL_TO_MATRIX_ELEMS_COUNT = 'Количество инициализирующих элементов не совпадает с количеством элементов матрицы!!The number of initializer elements must equal the number of elements in the matrix'; + TYPED_FILE_CANBE_OPENED_IN_SINGLEBYTE_ENCODING_ONLY = 'При открытии типизированного файла можно указывать только однобайтную кодировку!!Typed files can only be opened with single-byte encodings'; + BAD_ROW_INDEX = 'Один из элементов массива RowIndex выходит за пределы индексов строк двумерного массива!!An element in the RowIndex array is out of range for the matrix row indices'; + BAD_COL_INDEX = 'Один из элементов массива ColIndex выходит за пределы индексов столбцов двумерного массива!!An element in the ColIndex array is out of range for the matrix column indices'; + BAD_ROW_INDEX_FROM = 'FromRow выходит за пределы индексов строк двумерного массива!!FromRow is out of range for the matrix row indices'; + BAD_ROW_INDEX_TO = 'ToRow выходит за пределы индексов строк двумерного массива!!ToRow is out of range for the matrix row indices'; + BAD_COL_INDEX_FROM = 'FromCol выходит за пределы индексов строк двумерного массива!!FromCol is out of range for the matrix column indices'; + BAD_COL_INDEX_TO = 'ToCol выходит за пределы индексов строк двумерного массива!!ToCol is out of range for the matrix column indices'; + SLICE_SIZE_AND_RIGHT_VALUE_SIZE_MUST_BE_EQUAL = 'Размеры среза и присваиваемого выражения должны быть равны!!Slice size must match the size of the assigned expression'; MATR_DIMENSIONS_MUST_BE_EQUAL = 'Размеры матриц должны совпадать!!Matrix dimensions must be equal'; - COUNT_PARAMS_MAXFUN_MUSTBE_GREATER1 = 'Количество параметров функции Max должно быть > 1!!The number of parameters of the Max function must be > 1'; - COUNT_PARAMS_MINFUN_MUSTBE_GREATER1 = 'Количество параметров функции Min должно быть > 1!!The number of parameters of the Min function must be > 1'; - Format_InvalidString = 'Входная строка имела неверный формат!!Input string was not in a correct format'; + COUNT_PARAMS_MAXFUN_MUSTBE_GREATER1 = 'Количество параметров функции Max должно быть > 1!!Max function must have more than one parameter'; + COUNT_PARAMS_MINFUN_MUSTBE_GREATER1 = 'Количество параметров функции Min должно быть > 1!!Min function must have more than one parameter'; + Format_InvalidString = 'Входная строка имела неверный формат!!Input string was not in a valid format'; Overflow_Int32 = 'Целочисленное переполнение!!Integer overflow'; - FOR_STEP_CANNOT_BE_EQUAL0 = 'Шаг цикла for не может быт равен 0!!Step of the for loop cannot be equal to 0'; + FOR_STEP_CANNOT_BE_EQUAL0 = 'Шаг цикла for не может быт равен 0!!The step of a for loop cannot be 0'; SEQUENCE_CANNOT_BE_EMPTY = 'Последовательность не может быть пустой!!Sequence cannot be empty'; ARRAY_CANNOT_BE_EMPTY = 'Массив не может быть пустым!!Array cannot be empty'; + MIN_CANNOT_BE_GREATER_THAN_MAX = 'CLamp: min не может быть больше чем max!!CLamp: min cannot be greater than max'; // ----------------------------------------------------- // WINAPI // ----------------------------------------------------- @@ -14278,29 +14279,15 @@ begin Result := Range(0, Self - 1); end; -/// Возвращает число, ограниченное диапазоном от bottom до top включительно -function Clamp(Self: integer; bottom,top: integer): integer; extensionmethod; +/// Возвращает число, ограниченное диапазоном от min до max включительно +function Clamp(Self: integer; min,max: integer): integer; extensionmethod; begin - if Self < bottom then - Result := bottom - else if Self > top then - Result := top - else Result := Self; -end; - -/// Возвращает число, ограниченное величиной top сверху -function ClampTop(Self: integer; top: integer): integer; extensionmethod; -begin - if Self > top then - Result := top - else Result := Self; -end; - -/// Возвращает число, ограниченное величиной bottom снизу -function ClampBottom(Self: integer; bottom: integer): integer; extensionmethod; -begin - if Self < bottom then - Result := bottom + if min > max then + raise new System.ArgumentException(GetTranslation(MIN_CANNOT_BE_GREATER_THAN_MAX)); + if Self < min then + Result := min + else if Self > max then + Result := max else Result := Self; end; @@ -14395,33 +14382,18 @@ begin Result := Format('{0:f' + frac + '}', Self) end; -/// Возвращает число, ограниченное диапазоном от bottom до top включительно -function Clamp(Self: real; bottom,top: real): real; extensionmethod; +/// Возвращает число, ограниченное диапазоном от min до max включительно +function Clamp(Self: real; min,max: real): real; extensionmethod; begin - if Self < bottom then - Result := bottom - else if Self > top then - Result := top + if min > max then + raise new System.ArgumentException(GetTranslation(MIN_CANNOT_BE_GREATER_THAN_MAX)); + if Self < min then + Result := min + else if Self > max then + Result := max else Result := Self; end; -/// Возвращает число, ограниченное величиной top сверху -function ClampTop(Self: real; top: real): real; extensionmethod; -begin - if Self > top then - Result := top - else Result := Self; -end; - -/// Возвращает число, ограниченное величиной bottom снизу -function ClampBottom(Self: real; bottom: real): real; extensionmethod; -begin - if Self < bottom then - Result := bottom - else Result := Self; -end; - - //------------------------------------------------------------------------------ //>> Методы расширения типа char # Extension methods for char //------------------------------------------------------------------------------ diff --git a/bin/Lib/School.pas b/bin/Lib/School.pas index 68e10fc62..e404da46d 100644 --- a/bin/Lib/School.pas +++ b/bin/Lib/School.pas @@ -827,7 +827,7 @@ end; /// Первые k простых чисел function FirstPrimes(k: integer): List; begin - k := k.ClampTop(integer.MaxValue); // на всякий случай + // k := Min(k,integer.MaxValue); // на всякий случай if k <= nPrimeDivs then Result := LPrimes[:k] else begin diff --git a/bin/Lng/Eng/SemanticErrors_ms.dat b/bin/Lng/Eng/SemanticErrors_ms.dat index 2c4aab672..7b18091aa 100644 --- a/bin/Lng/Eng/SemanticErrors_ms.dat +++ b/bin/Lng/Eng/SemanticErrors_ms.dat @@ -3,7 +3,8 @@ CAN_NOT_READ=Can not read data of this type TUPLE_EXPECTED=Tuple expected TUPLE_OR_SEQUENCE_EXPECTED=Tuple or sequence expected TUPLE_OR_SEQUENCE_EXPECTED_FOREACH=Sequence of tuple or sequence expected -TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMRNT=Too many elements on the left side of tuple assignment +TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT=Too many elements on the left side of tuple assignment +TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_KEYVALUEPAIR_ASSIGNMENT=Too many elements on the left side of KeyValuePair assignment ONLY_BASE_ASSIGNMENT_FOR_TUPLE=Tuple allows only base assignment := TUPLE_TYPE_ERROR=Bad element in Tuple type INTEGER_VALUE_EXPECTED=Integer value expected diff --git a/bin/Lng/Rus/SemanticErrors_ms.dat b/bin/Lng/Rus/SemanticErrors_ms.dat index 0b3832901..92decb647 100644 --- a/bin/Lng/Rus/SemanticErrors_ms.dat +++ b/bin/Lng/Rus/SemanticErrors_ms.dat @@ -1,9 +1,10 @@ %PREFIX%=SEMANTICERROR_ CAN_NOT_READ=Нельзя считывать данные этого типа TUPLE_EXPECTED=Ожидался кортеж -TUPLE_OR_SEQUENCE_EXPECTED=Ожидался кортеж или последовательность -TUPLE_OR_SEQUENCE_EXPECTED_FOREACH=Ожидалась последовательность кортежей или последовательностей -TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMRNT=Слишком много переменных при распаковке кортежа +TUPLE_OR_SEQUENCE_EXPECTED=Ожидался кортеж или последовательность или пара (ключ,значение) +TUPLE_OR_SEQUENCE_EXPECTED_FOREACH=Ожидалась последовательность кортежей или последовательностей или пар (ключ,значение) +TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_TUPLE_ASSIGNMENT=Слишком много переменных при распаковке кортежа +TOO_MANY_ELEMENTS_ON_LEFT_SIDE_OF_KEYVALUEPAIR_ASSIGNMENT=Слишком много переменных при распаковке пары (ключ,значение) ONLY_BASE_ASSIGNMENT_FOR_TUPLE=Для кортежа допустимо только обычное присваивание := TUPLE_TYPE_ERROR=Ошибочная конструкция при построении типа кортежа INTEGER_VALUE_EXPECTED=Ожидалось значение целого типа