diff --git a/Configuration/GlobalAssemblyInfo.cs b/Configuration/GlobalAssemblyInfo.cs
index f438bea6a..dcbed8e97 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 = "11";
public const string Build = "0";
- public const string Revision = "3676";
+ public const string Revision = "3677";
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 d147780c6..b6f201d5a 100644
--- a/Configuration/Version.defs
+++ b/Configuration/Version.defs
@@ -1,4 +1,4 @@
-%COREVERSION%=0
-%REVISION%=3676
%MINOR%=11
+%REVISION%=3677
+%COREVERSION%=0
%MAJOR%=3
diff --git a/InstallerSamples/!Tutorial/06_ForWhileRepeat/For1.pas b/InstallerSamples/!Tutorial/06_ForWhileRepeat/For1.pas
index f2340e3a6..7e4bf5403 100644
--- a/InstallerSamples/!Tutorial/06_ForWhileRepeat/For1.pas
+++ b/InstallerSamples/!Tutorial/06_ForWhileRepeat/For1.pas
@@ -6,15 +6,14 @@ begin
Println('Числа от 1 до', n, ':');
for var i := 1 to n do
Print(i);
- Println;
- Println;
+ Println(NewLine);
+
Println('Числа от', n, 'до 1:');
for var i := n downto 1 do
Print(i);
- Println;
- Println;
+ Println(NewLine);
+
Println('Маленькие английские буквы:');
for var c := 'a' to 'z' do
Print(c);
- Println;
end.
diff --git a/InstallerSamples/!Tutorial/06_ForWhileRepeat/For2.pas b/InstallerSamples/!Tutorial/06_ForWhileRepeat/For2.pas
index af4eadebd..b762f62a0 100644
--- a/InstallerSamples/!Tutorial/06_ForWhileRepeat/For2.pas
+++ b/InstallerSamples/!Tutorial/06_ForWhileRepeat/For2.pas
@@ -8,7 +8,7 @@ begin
Println;
Print('Случайные целые от 1 до 99:');
- for var i := n downto 1 do
+ for var i := 1 to n do
Print(Random(1, 99));
Println;
end.
diff --git a/InstallerSamples/!Tutorial/06_ForWhileRepeat/Foreach1.pas b/InstallerSamples/!Tutorial/06_ForWhileRepeat/Foreach1.pas
new file mode 100644
index 000000000..eee8c2c3c
--- /dev/null
+++ b/InstallerSamples/!Tutorial/06_ForWhileRepeat/Foreach1.pas
@@ -0,0 +1,29 @@
+// Цикл foreach
+
+begin
+ // foreach по диапазону
+ foreach var x in 1..10 do
+ Print(x);
+ Println;
+
+ var a := [1,3,5,7,9];
+ // foreach по массиву
+ foreach var x in a do
+ Print(x);
+ Println;
+
+ // foreach с индексом
+ foreach var x in a index i do
+ Print((i,x));
+ Println;
+
+ // foreach по словарю
+ var d := Dict('cat' to 'кошка', 'dog' to 'собака');
+ foreach var kv in d do
+ Print(kv);
+ Println;
+
+ // foreach по словарю с распаковкой
+ foreach var (key,value) in d do
+ Println($'{key} → {value}');
+end.
diff --git a/InstallerSamples/!Tutorial/07_CharString/String5.pas b/InstallerSamples/!Tutorial/07_CharString/String5.pas
index 656769157..fa9635b98 100644
--- a/InstallerSamples/!Tutorial/07_CharString/String5.pas
+++ b/InstallerSamples/!Tutorial/07_CharString/String5.pas
@@ -4,9 +4,9 @@ var
s1: string := 'NET';
begin
- Writeln('Исходная строка: ''',s,'''');
+ Writeln('Исходная строка: ''',s,' ''');
s := Trim(s);
- Writeln('После вызова функции Trim: ''',s,'''');
+ Writeln('После вызова функции Trim: ''',s,' ''');
var p := Pos(s1,s);
WritelnFormat('Позиция подстроки ''{0}'' в строке ''{1}'' равна {2}',s1,s,p);
Delete(s,7,2);
diff --git a/InstallerSamples/!Tutorial/07_CharString/String6.pas b/InstallerSamples/!Tutorial/07_CharString/String6.pas
index 8c9ec80ac..8ea595464 100644
--- a/InstallerSamples/!Tutorial/07_CharString/String6.pas
+++ b/InstallerSamples/!Tutorial/07_CharString/String6.pas
@@ -4,9 +4,9 @@ var
s1: string := 'NET';
begin
- Writeln('Исходная строка: ''',s,'''');
+ Writeln('Исходная строка: ''',s,' ''');
s := s.Trim;
- Writeln('После вызова s.Trim: ''',s,'''');
+ Writeln('После вызова s.Trim: ''',s,' ''');
var p := s.IndexOf(s1); // Индексация - с нуля
WritelnFormat('Позиция подстроки ''{0}'' в строке ''{1}'' равна {2}',s1,s,p);
s := s.Remove(6,2);
diff --git a/InstallerSamples/!Tutorial/07_CharString/StringInteger1.pas b/InstallerSamples/!Tutorial/07_CharString/StringInteger1.pas
index 5c9dcd1d0..723eeeb7c 100644
--- a/InstallerSamples/!Tutorial/07_CharString/StringInteger1.pas
+++ b/InstallerSamples/!Tutorial/07_CharString/StringInteger1.pas
@@ -4,10 +4,10 @@ begin
// Преобразование целого в строку
var i := 234;
var s := IntToStr(i);
- WritelnFormat('Целое: {0}. После преобразования к строке: ''{1}''',i,s);
+ Println($'Целое: {i}. После преобразования к строке: ''{s}''');
// Преобразование строки в целое (может произойти исключение)
s := '567';
i := StrToInt(s);
- WritelnFormat('Строка: ''{0}''. После преобразования к целому: {1}',s,i);
+ Println($'Строка: ''{s}''. После преобразования к целому: {i}');
end.
\ No newline at end of file
diff --git a/InstallerSamples/!Tutorial/07_CharString/StringInteger2.pas b/InstallerSamples/!Tutorial/07_CharString/StringInteger2.pas
deleted file mode 100644
index 5dfe155aa..000000000
--- a/InstallerSamples/!Tutorial/07_CharString/StringInteger2.pas
+++ /dev/null
@@ -1,18 +0,0 @@
-// Преобразование целое <-> строка в старом стиле (Val и Str)
-var
- s: string;
- i: integer;
-
-begin
- // Преобразование целого в строку
- i := 234;
- Str(i,s);
- writelnFormat('Целое: {0}. После преобразования к строке: ''{1}''',i,s);
-
- // Преобразование строки в целое
- s := '567';
- var err: integer;
- Val(s,i,err);
- if err=0 then
- writelnFormat('Строка: ''{0}''. После преобразования к целому: {1}',s,i);
-end.
\ No newline at end of file
diff --git a/InstallerSamples/!Tutorial/07_CharString/StringInteger3.pas b/InstallerSamples/!Tutorial/07_CharString/StringInteger3.pas
index ce86a50a3..cb186ea96 100644
--- a/InstallerSamples/!Tutorial/07_CharString/StringInteger3.pas
+++ b/InstallerSamples/!Tutorial/07_CharString/StringInteger3.pas
@@ -1,16 +1,13 @@
-// Преобразование целое <-> строка в новом стиле
-var
- s: string;
- i: integer;
+// Преобразование целое <-> строка в новом стиле
begin
// Преобразование целого в строку
- i := 234;
- s := i.ToString;
- writelnFormat('Целое: {0}. После преобразования к строке: ''{1}''',i,s);
+ var i := 234;
+ var s := i.ToString;
+ Println($'Целое: {i}. После преобразования к строке: ''{s}''');
// Преобразование строки в целое
s := '567';
if integer.TryParse(s,i) then
- writelnFormat('Строка: ''{0}''. После преобразования к целому: {1}',s,i);
+ Println($'Строка: ''{s}''. После преобразования к целому: {i}');
end.
\ No newline at end of file
diff --git a/InstallerSamples/!Tutorial/07_CharString/StringReal1.pas b/InstallerSamples/!Tutorial/07_CharString/StringReal1.pas
index 4b1037b65..06eab8bc0 100644
--- a/InstallerSamples/!Tutorial/07_CharString/StringReal1.pas
+++ b/InstallerSamples/!Tutorial/07_CharString/StringReal1.pas
@@ -1,16 +1,13 @@
-// Преобразование вещественное <-> строка
-var
- s: string;
- r: real;
+// Преобразование вещественное <-> строка
begin
// Преобразование целого в строку
- r := 3.1415;
- s := FloatToStr(r);
- writelnFormat('Целое: {0}. После преобразования к строке: ''{1}''',r,s);
+ var r := 3.1415;
+ var s := FloatToStr(r);
+ Println($'Число: {r}. После преобразования к строке: ''{s}''');
// Преобразование строки в целое (может произойти исключение)
s := '3.1415';
r := StrToFloat(s);
- writelnFormat('Строка: ''{0}''. После преобразования к целому: {1}',s,r);
+ Println($'Строка: ''{s}''. После преобразования к числу: {r}');
end.
\ No newline at end of file
diff --git a/InstallerSamples/!Tutorial/07_CharString/UpLowCase.pas b/InstallerSamples/!Tutorial/07_CharString/UpLowCase.pas
index 2c7303586..c2dd3041d 100644
--- a/InstallerSamples/!Tutorial/07_CharString/UpLowCase.pas
+++ b/InstallerSamples/!Tutorial/07_CharString/UpLowCase.pas
@@ -1,22 +1,21 @@
-// Использование стандартных функций UpperCase, LowerCase
-var c: char;
+// Использование стандартных функций UpperCase, LowerCase
begin
- for c:='a' to 'z' do
- write(UpperCase(c));
- writeln;
- for c:='A' to 'Z' do
- write(LowerCase(c));
- writeln;
- for c:='А' to 'Я' do
- write(UpperCase(c));
- writeln;
- for c:='а' to 'я' do
- write(LowerCase(c));
- writeln;
+ for var c:='a' to 'z' do
+ Write(UpperCase(c));
+ Writeln;
+ for var c:='A' to 'Z' do
+ Write(LowerCase(c));
+ Writeln;
+ for var c:='А' to 'Я' do
+ Write(UpperCase(c));
+ Writeln;
+ for var c:='а' to 'я' do
+ Write(LowerCase(c));
+ Writeln;
var s := 'Папа у Васи силён в математике';
s := UpperCase(s);
- writeln(s);
+ Writeln(s);
s := LowerCase(s);
- writeln(s);
+ Writeln(s);
end.
diff --git a/InstallerSamples/!Tutorial/08_ProcFunc/Fun1.pas b/InstallerSamples/!Tutorial/08_ProcFunc/Fun1.pas
index 9aeffb0e6..d6b817adb 100644
--- a/InstallerSamples/!Tutorial/08_ProcFunc/Fun1.pas
+++ b/InstallerSamples/!Tutorial/08_ProcFunc/Fun1.pas
@@ -1,4 +1,4 @@
-// Определение функции. Вывод таблицы ее значений
+// Определение функции. Вывод таблицы ее значений
function MyFun(x: real): real;
begin
@@ -13,10 +13,10 @@ const
begin
var h := (b-a)/n;
var x := a;
- writeln('Таблица значений функции MyFun:');
+ Println('Таблица значений функции MyFun:');
for var i := 0 to n do
begin
- writeln(x:5:2,MyFun(x):10:4);
+ Println(x:5:2,MyFun(x):9:4);
x += h;
end;
end.
\ No newline at end of file
diff --git a/InstallerSamples/!Tutorial/08_ProcFunc/Fun2.pas b/InstallerSamples/!Tutorial/08_ProcFunc/Fun2.pas
index 4994822e4..231506521 100644
--- a/InstallerSamples/!Tutorial/08_ProcFunc/Fun2.pas
+++ b/InstallerSamples/!Tutorial/08_ProcFunc/Fun2.pas
@@ -1,4 +1,4 @@
-// Функция Power
+// Функция Power
function Power(x: real; n: integer): real;
begin
@@ -7,11 +7,8 @@ begin
Result *= x;
end;
-var
- x: real;
- n: integer;
-
begin
- x := 2; n := 5;
- writelnFormat('{0} в степени {1} = {2}',x,n,Power(x,n));
+ var x: real := 2;
+ var n: integer := 5;
+ Println($'{x} в степени {n} = {Power(x,n)}');
end.
\ No newline at end of file
diff --git a/InstallerSamples/!Tutorial/08_ProcFunc/Proc1.pas b/InstallerSamples/!Tutorial/08_ProcFunc/Proc1.pas
index 95f40b8a0..fe5a5e8cd 100644
--- a/InstallerSamples/!Tutorial/08_ProcFunc/Proc1.pas
+++ b/InstallerSamples/!Tutorial/08_ProcFunc/Proc1.pas
@@ -1,17 +1,17 @@
-// Параметры процедур
+// Параметры процедур
procedure Operations(a,b: integer);
begin
- writeln(a,' + ',b,' = ',a+b);
- writeln(a,' - ',b,' = ',a-b);
- writeln(a,' * ',b,' = ',a*b);
- writeln(a,' / ',b,' = ',a/b);
- writeln(a,' div ',b,' = ',a div b);
- writeln(a,' mod ',b,' = ',a mod b);
+ Println(a,'+',b,'=',a+b);
+ Println(a,'-',b,'=',a-b);
+ Println(a,'*',b,'=',a*b);
+ Println(a,'/',b,'=',a/b);
+ Println(a,'div',b,'=',a div b);
+ Println(a,'mod',b,'=',a mod b);
end;
begin
Operations(5,3);
- writeln;
+ Println;
Operations(7,4);
end.
\ No newline at end of file
diff --git a/InstallerSamples/!Tutorial/08_ProcFunc/Proc2.pas b/InstallerSamples/!Tutorial/08_ProcFunc/Proc2.pas
index c62936635..a77214f03 100644
--- a/InstallerSamples/!Tutorial/08_ProcFunc/Proc2.pas
+++ b/InstallerSamples/!Tutorial/08_ProcFunc/Proc2.pas
@@ -6,17 +6,14 @@ begin
m := a mod b;
end;
-var
- a,b: integer;
- d,m: integer;
-
begin
- a := 7;
- b := 3;
+ var a := 7;
+ var b := 3;
+ var d,m: integer;
DivMod(a,b,d,m);
- writelnFormat('{0} div {1} = {2}; {0} mod {1} = {3}',a,b,d,m);
+ Println($'{a} div {b} = {d}; {a} mod {b} = {m}');
a := 23;
b := 5;
DivMod(a,b,d,m);
- writelnFormat('{0} div {1} = {2}; {0} mod {1} = {3}',a,b,d,m);
+ Println($'{a} div {b} = {d}; {a} mod {b} = {m}');
end.
\ No newline at end of file
diff --git a/InstallerSamples/!Tutorial/08_ProcFunc/Proc3.pas b/InstallerSamples/!Tutorial/08_ProcFunc/Proc3.pas
index ccbdb03a0..29443f97a 100644
--- a/InstallerSamples/!Tutorial/08_ProcFunc/Proc3.pas
+++ b/InstallerSamples/!Tutorial/08_ProcFunc/Proc3.pas
@@ -1,4 +1,4 @@
-// Упаковка параметров в запись
+// Упаковка параметров в запись
uses GraphABC;
type
diff --git a/InstallerSamples/!Tutorial/08_ProcFunc/Proc4.pas b/InstallerSamples/!Tutorial/08_ProcFunc/Proc4.pas
new file mode 100644
index 000000000..5f632eb06
--- /dev/null
+++ b/InstallerSamples/!Tutorial/08_ProcFunc/Proc4.pas
@@ -0,0 +1,18 @@
+// Упаковка параметров в класс
+uses GraphWPF;
+
+type
+ Point = auto class
+ x,y: integer;
+ end;
+
+procedure Line(p1,p2: Point) := Line(p1.x,p1.y,p2.x,p2.y);
+
+begin
+ var p1 := new Point(10,10);
+ var p2 := new Point(10,210);
+ var p3 := new Point(210,10);
+ Line(p1,p2);
+ Line(p2,p3);
+ Line(p3,p1);
+end.
\ No newline at end of file
diff --git a/PABCNetHelp/LangGuide/PABCSystemUnit/Files/Extension methods for IDictionary.html b/PABCNetHelp/LangGuide/PABCSystemUnit/Files/Extension methods for IDictionary.html
index 30d1be592..3f73c528d 100644
--- a/PABCNetHelp/LangGuide/PABCSystemUnit/Files/Extension methods for IDictionary.html
+++ b/PABCNetHelp/LangGuide/PABCSystemUnit/Files/Extension methods for IDictionary.html
@@ -2,6 +2,7 @@
+
@@ -16,6 +17,10 @@
function Get<Key, Value>(Self: IDictionary<Key, Value>; K: Key; V: Value := default(Value)): Value;
function GetOrAdd<Key, Value>(Self: IDictionary<Key, Value>; K: Key; valueFactory: Key -> Value): Value;
+function GetOrAdd<Key, Value>(Self: IDictionary<Key, Value>; K: Key; defaultValue: Value): Value;
+function operator-<TKey, TVal>(Self: Dictionary<TKey, TVal>; key: TKey): Dictionary<TKey, TVal>;
function operator-<TKey, TVal>(Self: Dictionary<TKey, TVal>; keys: sequence of TKey): Dictionary<TKey, TVal>;
diff --git a/PABCNetHelp/LangGuide/PABCSystemUnit/Files/Extension methods for string.html b/PABCNetHelp/LangGuide/PABCSystemUnit/Files/Extension methods for string.html
index e82ff4112..89e8536db 100644
--- a/PABCNetHelp/LangGuide/PABCSystemUnit/Files/Extension methods for string.html
+++ b/PABCNetHelp/LangGuide/PABCSystemUnit/Files/Extension methods for string.html
@@ -35,6 +35,8 @@
function CountOf(Self: string; substring: string; allowOverlap: boolean := false): integer;
function CountOf(Self: string; c: char): integer;
+function IndicesOf(Self, SubS: string; overlay: boolean := False): sequence of integer;
function InRange(Self: string; a, b: string): boolean;
diff --git a/Release/pabcversion.txt b/Release/pabcversion.txt
index 4dd76ab74..34a3ac014 100644
--- a/Release/pabcversion.txt
+++ b/Release/pabcversion.txt
@@ -1 +1 @@
-3.11.0.3676
+3.11.0.3677
diff --git a/ReleaseGenerators/PascalABCNET_version.nsh b/ReleaseGenerators/PascalABCNET_version.nsh
index 85fe93a58..e756d98d6 100644
--- a/ReleaseGenerators/PascalABCNET_version.nsh
+++ b/ReleaseGenerators/PascalABCNET_version.nsh
@@ -1 +1 @@
-!define VERSION '3.11.0.3676'
+!define VERSION '3.11.0.3677'
diff --git a/TestSuite/CompilationSamples/PABCSystem.pas b/TestSuite/CompilationSamples/PABCSystem.pas
index d41300d78..4bcbeb4c7 100644
--- a/TestSuite/CompilationSamples/PABCSystem.pas
+++ b/TestSuite/CompilationSamples/PABCSystem.pas
@@ -3292,6 +3292,7 @@ const
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';
+ SUBSTRING_CANNOT_BE_EMPTY = 'Подстрока не может быть пустой!!Substring cannot be empty';
// -----------------------------------------------------
// WINAPI
// -----------------------------------------------------
@@ -15078,26 +15079,51 @@ end;
function CountOf(Self: string; substring: string; allowOverlap: boolean := false): integer; extensionmethod;
begin
if string.IsNullOrEmpty(substring) then
- raise new System.ArgumentException('Подстрока не может быть пустой');
+ raise new System.ArgumentException(GetTranslation(SUBSTRING_CANNOT_BE_EMPTY));
Result := 0;
- var index := 0;
- var substringLength := substring.Length;
+ var i := 1;
+ var m := substring.Length;
+ var n := Self.Length;
- while true do
+ if (m = 0) or (m > n) then exit;
+
+ var lastPossible := n - m + 1;
+
+ while i <= lastPossible do
begin
- index := Self.IndexOf(substring, index);
- if index = -1 then
- break;
+ var isMatch := True;
+ // Проверяем первый символ до цикла - это частый случай несовпадения
+ if Self[i] <> substring[1] then
+ isMatch := False
+ else
+ for var j := 2 to m do
+ if Self[i + j - 1] <> substring[j] then
+ begin
+ isMatch := False;
+ break;
+ end;
- Result += 1;
-
- if allowOverlap then
- index += 1 // Для пересекающихся вхождений сдвигаем на 1 символ
- else index += substringLength; // Для непересекающихся - на длину подстроки
+ if isMatch then
+ begin
+ Result += 1;
+ if allowOverlap then
+ i += 1
+ else i += m;
+ end
+ else i += 1;
end;
end;
+/// Возвращает количество вхождений символа в строку
+function CountOf(Self: string; c: char): integer; extensionmethod;
+begin
+ Result := 0;
+ for var i:=1 to Self.Length do
+ if Self[i] = c then
+ Result += 1;
+end;
+
///--
function CreateSliceFromStringInternal(Self: string; from, step, count: integer): string;
@@ -15324,6 +15350,26 @@ begin
Result := V;
end;
+/// Получает значение по ключу или добавляет новое, если ключ отсутствует
+function GetOrAdd