SPython: неявное преобразование int в bool и bool в int (#3383)

* Implement bool to int and int to bool implicit conversion for SPython

* Change "and", "or" and "not" operations to be logical in SPython

* Add standard functions' overloads (all, any, sum)
This commit is contained in:
Александр Земляк 2026-02-02 12:01:18 +03:00 committed by GitHub
parent dad4bf4f4b
commit 2c30b73b08
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 187 additions and 71 deletions

View file

@ -506,11 +506,15 @@ expr
}
| expr AND expr
{
$$ = new bin_expr($1, $3, $2.type, @$);
$$ = new bin_expr(SubtreeCreator.CreateMethodCall("bool", $1.source_context, $1),
SubtreeCreator.CreateMethodCall("bool", $3.source_context, $3),
$2.type, @$);
}
| expr OR expr
{
$$ = new bin_expr($1, $3, $2.type, @$);
$$ = new bin_expr(SubtreeCreator.CreateMethodCall("bool", $1.source_context, $1),
SubtreeCreator.CreateMethodCall("bool", $3.source_context, $3),
$2.type, @$);
}
| expr SLASHSLASH expr
{
@ -542,9 +546,7 @@ expr
}
| expr STARSTAR expr
{
addressed_value method_name = new ident("!pow", @$);
expression_list el = new expression_list(new List<expression> { $1, $3 }, @$);
$$ = new method_call(method_name, el, @$);
$$ = SubtreeCreator.CreateMethodCall("!pow", @$, $1, $3);
}
| expr IN expr
{
@ -561,7 +563,7 @@ expr
}
| NOT expr
{
$$ = new un_expr($2, $1.type, @$);
$$ = new un_expr(SubtreeCreator.CreateMethodCall("bool", $2.source_context, $2), $1.type, @$);
}
| BINNOT expr
{
@ -817,12 +819,12 @@ variable
// list generator
| LBRACKET generator_object RBRACKET
{
$$ = new method_call(new ident("list", $2.source_context), new expression_list($2, $2.source_context), $2.source_context);
$$ = SubtreeCreator.CreateMethodCall("list", $2.source_context, $2);
}
// set generator
| LBRACE generator_object RBRACE
{
$$ = new method_call(new ident("set", $2.source_context), new expression_list($2, $2.source_context), $2.source_context);
$$ = SubtreeCreator.CreateMethodCall("set", $2.source_context, $2);
}
// dict generator
| LBRACE generator_object_for_dict RBRACE
@ -862,11 +864,11 @@ generator_object_for_dict
dict_constant
: LBRACE expr_mapping_list RBRACE
{
$$ = new method_call(new ident("dict", @$), $2 as expression_list, @$);
$$ = SubtreeCreator.CreateMethodCall("dict", @$, (expression_list)$2);
}
| LBRACE RBRACE
{
$$ = new method_call(new ident("!empty_dict", @$), null, @$);
$$ = SubtreeCreator.CreateMethodCall("!empty_dict", @$);
}
;
@ -874,7 +876,7 @@ set_constant
: LBRACE expr_list RBRACE
{
var acn = new array_const_new($2 as expression_list, '|', @$);
$$ = new method_call(new ident("set", @$), new expression_list(acn, @$), @$);
$$ = SubtreeCreator.CreateMethodCall("set", @$, acn);
}
;
@ -882,11 +884,11 @@ list_constant
: LBRACKET expr_list RBRACKET
{
var acn = new array_const_new($2 as expression_list, '|', @$);
$$ = new method_call(new ident("list", @$), new expression_list(acn, @$), @$);
$$ = SubtreeCreator.CreateMethodCall("list", @$, acn);
}
| LBRACKET RBRACKET
{
$$ = new method_call(new ident("!empty_list", @$), null, @$);
$$ = SubtreeCreator.CreateMethodCall("!empty_list", @$);
}
;

View file

@ -4,7 +4,7 @@
// GPPG version 1.3.6
// Machine: DESKTOP-V3E9T2U
// DateTime: 15.12.2025 12:38:14
// DateTime: 29.01.2026 14:12:59
// UserName: alex
// Input file <SPythonParser.y>
@ -1052,12 +1052,16 @@ public partial class SPythonGPPGParser: ShiftReduceParser<ValueType, LexLocation
break;
case 80: // expr -> expr, AND, expr
{
CurrentSemanticValue.ex = new bin_expr(ValueStack[ValueStack.Depth-3].ex, ValueStack[ValueStack.Depth-1].ex, ValueStack[ValueStack.Depth-2].op.type, CurrentLocationSpan);
CurrentSemanticValue.ex = new bin_expr(SubtreeCreator.CreateMethodCall("bool", ValueStack[ValueStack.Depth-3].ex.source_context, ValueStack[ValueStack.Depth-3].ex),
SubtreeCreator.CreateMethodCall("bool", ValueStack[ValueStack.Depth-1].ex.source_context, ValueStack[ValueStack.Depth-1].ex),
ValueStack[ValueStack.Depth-2].op.type, CurrentLocationSpan);
}
break;
case 81: // expr -> expr, OR, expr
{
CurrentSemanticValue.ex = new bin_expr(ValueStack[ValueStack.Depth-3].ex, ValueStack[ValueStack.Depth-1].ex, ValueStack[ValueStack.Depth-2].op.type, CurrentLocationSpan);
CurrentSemanticValue.ex = new bin_expr(SubtreeCreator.CreateMethodCall("bool", ValueStack[ValueStack.Depth-3].ex.source_context, ValueStack[ValueStack.Depth-3].ex),
SubtreeCreator.CreateMethodCall("bool", ValueStack[ValueStack.Depth-1].ex.source_context, ValueStack[ValueStack.Depth-1].ex),
ValueStack[ValueStack.Depth-2].op.type, CurrentLocationSpan);
}
break;
case 82: // expr -> expr, SLASHSLASH, expr
@ -1097,9 +1101,7 @@ public partial class SPythonGPPGParser: ShiftReduceParser<ValueType, LexLocation
break;
case 89: // expr -> expr, STARSTAR, expr
{
addressed_value method_name = new ident("!pow", CurrentLocationSpan);
expression_list el = new expression_list(new List<expression> { ValueStack[ValueStack.Depth-3].ex, ValueStack[ValueStack.Depth-1].ex }, CurrentLocationSpan);
CurrentSemanticValue.ex = new method_call(method_name, el, CurrentLocationSpan);
CurrentSemanticValue.ex = SubtreeCreator.CreateMethodCall("!pow", CurrentLocationSpan, ValueStack[ValueStack.Depth-3].ex, ValueStack[ValueStack.Depth-1].ex);
}
break;
case 90: // expr -> expr, IN, expr
@ -1120,7 +1122,7 @@ public partial class SPythonGPPGParser: ShiftReduceParser<ValueType, LexLocation
break;
case 93: // expr -> NOT, expr
{
CurrentSemanticValue.ex = new un_expr(ValueStack[ValueStack.Depth-1].ex, ValueStack[ValueStack.Depth-2].op.type, CurrentLocationSpan);
CurrentSemanticValue.ex = new un_expr(SubtreeCreator.CreateMethodCall("bool", ValueStack[ValueStack.Depth-1].ex.source_context, ValueStack[ValueStack.Depth-1].ex), ValueStack[ValueStack.Depth-2].op.type, CurrentLocationSpan);
}
break;
case 94: // expr -> BINNOT, expr
@ -1361,12 +1363,12 @@ public partial class SPythonGPPGParser: ShiftReduceParser<ValueType, LexLocation
break;
case 138: // variable -> LBRACKET, generator_object, RBRACKET
{
CurrentSemanticValue.ex = new method_call(new ident("list", ValueStack[ValueStack.Depth-2].ex.source_context), new expression_list(ValueStack[ValueStack.Depth-2].ex, ValueStack[ValueStack.Depth-2].ex.source_context), ValueStack[ValueStack.Depth-2].ex.source_context);
CurrentSemanticValue.ex = SubtreeCreator.CreateMethodCall("list", ValueStack[ValueStack.Depth-2].ex.source_context, ValueStack[ValueStack.Depth-2].ex);
}
break;
case 139: // variable -> LBRACE, generator_object, RBRACE
{
CurrentSemanticValue.ex = new method_call(new ident("set", ValueStack[ValueStack.Depth-2].ex.source_context), new expression_list(ValueStack[ValueStack.Depth-2].ex, ValueStack[ValueStack.Depth-2].ex.source_context), ValueStack[ValueStack.Depth-2].ex.source_context);
CurrentSemanticValue.ex = SubtreeCreator.CreateMethodCall("set", ValueStack[ValueStack.Depth-2].ex.source_context, ValueStack[ValueStack.Depth-2].ex);
}
break;
case 140: // variable -> LBRACE, generator_object_for_dict, RBRACE
@ -1400,29 +1402,29 @@ public partial class SPythonGPPGParser: ShiftReduceParser<ValueType, LexLocation
break;
case 145: // dict_constant -> LBRACE, expr_mapping_list, RBRACE
{
CurrentSemanticValue.ex = new method_call(new ident("dict", CurrentLocationSpan), ValueStack[ValueStack.Depth-2].stn as expression_list, CurrentLocationSpan);
CurrentSemanticValue.ex = SubtreeCreator.CreateMethodCall("dict", CurrentLocationSpan, (expression_list)ValueStack[ValueStack.Depth-2].stn);
}
break;
case 146: // dict_constant -> LBRACE, RBRACE
{
CurrentSemanticValue.ex = new method_call(new ident("!empty_dict", CurrentLocationSpan), null, CurrentLocationSpan);
CurrentSemanticValue.ex = SubtreeCreator.CreateMethodCall("!empty_dict", CurrentLocationSpan);
}
break;
case 147: // set_constant -> LBRACE, expr_list, RBRACE
{
var acn = new array_const_new(ValueStack[ValueStack.Depth-2].stn as expression_list, '|', CurrentLocationSpan);
CurrentSemanticValue.ex = new method_call(new ident("set", CurrentLocationSpan), new expression_list(acn, CurrentLocationSpan), CurrentLocationSpan);
CurrentSemanticValue.ex = SubtreeCreator.CreateMethodCall("set", CurrentLocationSpan, acn);
}
break;
case 148: // list_constant -> LBRACKET, expr_list, RBRACKET
{
var acn = new array_const_new(ValueStack[ValueStack.Depth-2].stn as expression_list, '|', CurrentLocationSpan);
CurrentSemanticValue.ex = new method_call(new ident("list", CurrentLocationSpan), new expression_list(acn, CurrentLocationSpan), CurrentLocationSpan);
CurrentSemanticValue.ex = SubtreeCreator.CreateMethodCall("list", CurrentLocationSpan, acn);
}
break;
case 149: // list_constant -> LBRACKET, RBRACKET
{
CurrentSemanticValue.ex = new method_call(new ident("!empty_list", CurrentLocationSpan), null, CurrentLocationSpan);
CurrentSemanticValue.ex = SubtreeCreator.CreateMethodCall("!empty_list", CurrentLocationSpan);
}
break;
case 150: // optional_condition -> /* empty */

View file

@ -1,12 +1,11 @@
using System.Collections.Generic;
using PascalABCCompiler.Errors;
using PascalABCCompiler.SemanticTree;
using PascalABCCompiler.SyntaxTree;
using PascalABCCompiler.SystemLibrary;
using PascalABCCompiler.TreeConverter;
using PascalABCCompiler.TreeRealization;
using PascalABCCompiler.Errors;
using System.ComponentModel.Design;
using System;
using System.Collections.Generic;
namespace SPythonSyntaxTreeVisitor
{
@ -27,6 +26,52 @@ namespace SPythonSyntaxTreeVisitor
OnLeave = RunAdditionalChecks;
}
type_intersection_node boolToIntIntersectionPrev;
type_intersection_node intToBoolIntersectionPrev;
public override void BeforeCompilationActions()
{
base.BeforeCompilationActions();
UpdateStandardTypes();
}
public override void PostCompilationActions()
{
base.PostCompilationActions();
RestoreStandardTypes();
}
private void UpdateStandardTypes()
{
// Неявное преобразование из int в bool и из bool в int
boolToIntIntersectionPrev = SystemLibrary.bool_type.remove_intersection_node(SystemLibrary.integer_type);
intToBoolIntersectionPrev = SystemLibrary.integer_type.remove_intersection_node(SystemLibrary.bool_type);
var newIntersection = new type_intersection_node(type_compare.less_type);
newIntersection.this_to_another = new type_conversion(new basic_function_node(basic_function_type.booltoi, SystemLibrary.integer_type, false), false);
newIntersection.another_to_this = new type_conversion(new basic_function_node(basic_function_type.itobool, SystemLibrary.bool_type, false), false);
SystemLibrary.bool_type.add_intersection_node(SystemLibrary.integer_type, newIntersection, false);
}
private void RestoreStandardTypes()
{
SystemLibrary.bool_type.remove_intersection_node(SystemLibrary.integer_type);
if (boolToIntIntersectionPrev != null)
SystemLibrary.bool_type.add_intersection_node(SystemLibrary.integer_type, boolToIntIntersectionPrev, false);
if (intToBoolIntersectionPrev != null)
SystemLibrary.integer_type.add_intersection_node(SystemLibrary.bool_type, intToBoolIntersectionPrev, false);
}
private void RunAdditionalChecks(syntax_tree_node node)
{
switch (node)

View file

@ -57,8 +57,12 @@ namespace PascalABCCompiler.TreeConverter
syntaxTreeVisitor.DirectivesToNodesLinks = CompilerDirectivesToSyntaxTreeNodesLinker.BuildLinks(initializationData.syntaxUnit, initializationData.errorsList); //MikhailoMMX добавил передачу списка ошибок (02.10.10)
syntaxTreeVisitor.BeforeCompilationActions();
syntaxTreeVisitor.ProcessNode(initializationData.syntaxUnit);
syntaxTreeVisitor.PostCompilationActions();
CompiledVariables.AddRange(syntaxTreeVisitor.CompiledVariables);
return syntaxTreeVisitor.CompiledUnit;
@ -75,9 +79,13 @@ namespace PascalABCCompiler.TreeConverter
foreach (SyntaxTree.compiler_directive cd in initializationData.syntaxUnit.compiler_directives)
cd.visit(syntaxTreeVisitor);
syntaxTreeVisitor.visit_implementation(initializationData.syntaxUnit as SyntaxTree.unit_module);
CompiledVariables.AddRange(syntaxTreeVisitor.CompiledVariables);
syntaxTreeVisitor.BeforeCompilationActions();
syntaxTreeVisitor.visit_implementation(initializationData.syntaxUnit as SyntaxTree.unit_module);
syntaxTreeVisitor.PostCompilationActions();
CompiledVariables.AddRange(syntaxTreeVisitor.CompiledVariables);
}
public void Reset()

View file

@ -54,7 +54,7 @@ namespace PascalABCCompiler.SemanticTree
sbtos, sbtoi, sbtol, sbtof, sbtod, sbtob, sbtous, sbtoui, sbtoul, sbtochar,//signed byte to short, int, long, float, double
stoi, stol, stof, stod, stob, stosb, stous, stoui, stoul, stochar, //short to ...
ustoi, ustoui, ustol, ustoul, ustof, ustod, ustob, ustosb, ustos, ustochar, //unsigned short to ...
itol, itof, itod, itob, itosb, itos, itous, itoui, itoul, itochar, //integer to ...
itol, itof, itod, itob, itosb, itos, itous, itoui, itoul, itochar, itobool, //integer to ...
uitol, uitoul, uitob, uitosb, uitos, uitous, uitoi, uitof, uitod, uitochar, //uint to ...
ltof, ltod, ltob, ltosb, ltos, ltous, ltoi, ltoui, ltoul, ltochar, //long to ...
ultob, ultosb, ultos, ultous, ultoi, ultoui, ultol, ultochar, ultof, ultod, //ulong to ...

View file

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PascalABCCompiler.SyntaxTree
{
@ -11,7 +10,7 @@ namespace PascalABCCompiler.SyntaxTree
/// <summary>
/// Класс для генерации новых узлов синтаксического дерева
/// </summary>
public class SyntaxTreeNodesConstructor
public static class SyntaxTreeNodesConstructor
{
public static var_statement CreateVarStatementNode(string idName, type_definition varType, expression initValue)
{
@ -97,7 +96,7 @@ namespace PascalABCCompiler.SyntaxTree
}
#endregion
public class SubtreeCreator
public static class SubtreeCreator
{
/// <summary>
/// Создать var-выражение
@ -264,10 +263,10 @@ namespace PascalABCCompiler.SyntaxTree
/// <returns></returns>
public static method_call CreateSystemFunctionCall(string funcName, params expression[] exprList)
{
return CreateMethodCall(funcName, "PABCSystem", exprList);
return CreateMethodCallWithQualifier(funcName, "PABCSystem", exprList);
}
public static method_call CreateMethodCall(string funcName, string qualifier, params expression[] exprList)
public static method_call CreateMethodCallWithQualifier(string funcName, string qualifier, params expression[] exprList)
{
var methodCall = CreateMethodCall(funcName, exprList);
methodCall.dereferencing_value = new dot_node(new ident(qualifier), new ident(funcName));
@ -282,10 +281,27 @@ namespace PascalABCCompiler.SyntaxTree
}
private static method_call CreateMethodCall(string methodName, params expression[] exprList)
{
return CreateMethodCall(methodName, null, exprList);
}
public static method_call CreateMethodCall(string methodName, SourceContext sc, expression_list expr_list)
{
SyntaxTree.method_call mc = new SyntaxTree.method_call();
mc.dereferencing_value = new ident(methodName);
mc.source_context = sc;
mc.dereferencing_value = new ident(methodName, sc);
mc.parameters = expr_list;
return mc;
}
public static method_call CreateMethodCall(string methodName, SourceContext sc, params expression[] exprList)
{
SyntaxTree.method_call mc = new SyntaxTree.method_call();
mc.source_context = sc;
mc.dereferencing_value = new ident(methodName, sc);
SyntaxTree.expression_list exl = new PascalABCCompiler.SyntaxTree.expression_list();
exl.source_context = sc;
foreach (expression x in exprList)
exl.Add(x);
mc.parameters = exl;
@ -352,7 +368,7 @@ namespace PascalABCCompiler.SyntaxTree
return res;
}
}
public class SyntaxTreeBuilder
public static class SyntaxTreeBuilder
{
public static SourceContext BuildGenSC = new SourceContext(0, 777777, 0, 0, 0, 0);

View file

@ -625,7 +625,7 @@ namespace SyntaxVisitors.PatternsVisitors
}
var deconstructCall = new procedure_call();
deconstructCall.func_name = SubtreeCreator.CreateMethodCall(DeconstructMethodName, castVariableName.name, parameters.Select(x => x.identifier).ToArray());
deconstructCall.func_name = SubtreeCreator.CreateMethodCallWithQualifier(DeconstructMethodName, castVariableName.name, parameters.Select(x => x.identifier).ToArray());
desugarResult.DeconstructCall = deconstructCall;
return desugarResult;

View file

@ -0,0 +1,16 @@
# int to bool and bool to int implicit conversion
a: int = True
b: bool = 5
if 10:
print((1 > 0) + 1)
while 0:
print('Infinite loop')
print(bool(1))
print(filter(bool, [0, 1, 2]))
print(all([0, 1, 3]))
print(sum([True, False, True]))

View file

@ -171,6 +171,16 @@ namespace PascalABCCompiler.TreeConverter
context.syntax_tree_visitor = this;
}
/// <summary>
/// Можно переопределять для добавления действий перед конвертацией интерфейсной и имплементационной частей
/// </summary>
public virtual void BeforeCompilationActions() { }
/// <summary>
/// Можно переопределять для добавления действий после конвертации интерфейсной и имплементационной частей
/// </summary>
public virtual void PostCompilationActions() { }
public List<TreeRealization.var_definition_node> CompiledVariables => compiledVariables;
public string UniqueNumStr()

View file

@ -317,6 +317,26 @@ namespace PascalABCCompiler.TreeRealization
generated_type_intersections.Add(tn);
}
}
/// <summary>
/// Удаляет узел пересечения текущего типа и типа tn.
/// Возвращает удаленный узел (или null).
/// </summary>
public type_intersection_node remove_intersection_node(type_node tn, bool is_generated = false)
{
var intersection = get_type_intersection(tn);
if (intersection != null)
{
type_intersections.Remove(tn);
if (is_generated)
generated_type_intersections.Remove(tn);
}
return intersection;
}
public void clear_generated_intersections()
{
if (generated_type_intersections == null || type_intersections == null)

View file

@ -44,7 +44,9 @@ type kwargs_gen<T> = class
end;
function all(s: sequence of boolean): boolean;
function all(s: sequence of integer): boolean;
function any(s: sequence of boolean): boolean;
function any(s: sequence of integer): boolean;
function enumerate<T>(s: sequence of T; start: integer := 0): sequence of (integer,T);
function filter<T>(cond: T -> boolean; s: sequence of T): sequence of T;
@ -55,6 +57,16 @@ function int(val: string): integer;
function int(val: real): integer;
function int(b: boolean): integer;
function str(val: object): string;
function float(val: string): real;
function float(x: integer): real;
function bool(val: integer): boolean;
function round(val: real): integer;
function split(s: string): sequence of string;
@ -64,15 +76,6 @@ function get_values<K, V>(dct: Dictionary<K, V>): sequence of V;
function &type(obj: object): string;
//function int(val: string): integer;
function int(b: boolean): integer;
function str(val: object): string;
function float(val: string): real;
function float(x: integer): real;
// Basic sequence functions
function range(s: integer; e: integer; step: integer): sequence of integer;
@ -87,10 +90,6 @@ function !format(i: integer; fmt: string): string;
function !format(val: real; fmt: string): string;
//function all<T>(seq: sequence of T): boolean;
//function any<T>(seq: sequence of T): boolean;
//------------------------------------
// Standard Math functions
//------------------------------------
@ -110,7 +109,7 @@ function pow(x: real; n: integer): real;
/// Возвращает x в целой степени n
function pow(x: BigInteger; n: integer): BigInteger;
// function floor(x: real): real;
{$region STANDARD CONTAINERS}
type list<T> = class(IEnumerable<T>)
private
@ -490,6 +489,8 @@ type dict<K, V> = class(IEnumerable<PABCSystem.KeyValuePair<K, V>>)
function System.Collections.IEnumerable.GetEnumerator() : System.Collections.IEnumerator := GetEnumerator();
end;
{$endregion STANDARD CONTAINERS}
//Standard functions with Lists
function len<T>(lst: list<T>): integer;
@ -498,13 +499,11 @@ function len<K, V>(dct: dict<K, V>): integer;
function len<T>(arr: array of T): integer;
function len(s: string): integer;
// function &set<T>(sq: sequence of T): &set<T>;
function sorted<T>(lst: list<T>): list<T>;
function sum(lst: sequence of integer): integer;
function sum(lst: sequence of real): real;
function sum(s: sequence of boolean): integer;
function sum(s: sequence of integer): integer;
function sum(s: sequence of real): real;
function !assign<T>(var a: T; b: T): T;
@ -645,6 +644,8 @@ function float(val: string): real := real.Parse(val);
function float(x: integer): real := PABCSystem.Floor(x);
function bool(val: integer): boolean := Convert.ToBoolean(val);
function range(s: integer; e: integer; step: integer): sequence of integer;
begin
Result := PABCSystem.Range(s, e - PABCSystem.Sign(step), step);
@ -660,10 +661,6 @@ begin
Result := PABCSystem.Range(0, e - 1);
end;
//function all<T>(seq: sequence of T): boolean := seq.All(x -> x);
//function any<T>(seq: sequence of T): boolean := seq.Any(x -> x);
//------------------------------------
// Standard Math functions
//------------------------------------
@ -694,8 +691,9 @@ begin
Result := newList;
end;
function sum(lst: sequence of integer): integer := lst.sum();
function sum(lst: sequence of real): real := lst.sum();
function sum(s: sequence of boolean): integer := s.Select(x -> Convert.ToInt32(x)).Sum();
function sum(s: sequence of integer): integer := s.Sum();
function sum(s: sequence of real): real := s.Sum();
function !assign<T>(var a: T; b: T): T;
begin
@ -811,11 +809,6 @@ function CreateTuple<T1, T2, T3, T4, T5, T6, T7>(
// TUPLES END
//function &set<T>(sq: sequence of T): &set<T>;
//begin
// Result := new &set<T>(sq);
//end;
function all(s: sequence of boolean): boolean;
begin
Result := true;
@ -827,6 +820,8 @@ begin
end;
end;
function all(s: sequence of integer): boolean := all(s.Select(x -> Convert.ToBoolean(x)));
function any(s: sequence of boolean): boolean;
begin
Result := false;
@ -838,6 +833,8 @@ begin
end;
end;
function any(s: sequence of integer): boolean := any(s.Select(x -> Convert.ToBoolean(x)));
///-
function ToDictionary<T, U>(Self: sequence of System.Tuple<T, U>): dict<T, U>; extensionmethod;
begin