unit ASFunctions;

{ **************************************************************************** }
{ Rejbrand AlgoSim Kernel Functions                                            }
{ Copyright © 2018–2025 Andreas Rejbrand                                       }
{ https://english.rejbrand.se/                                                 }
{ **************************************************************************** }

{$WARN SYMBOL_PLATFORM OFF}
{$WARN DUPLICATE_CTOR_DTOR OFF}

interface

uses
  SysUtils, Types, Classes, Character, ASNum, ASTree, ASKernelDefs, ASObjects,
  ASObjStore, ASStructs, ASExpression, ASFcnMgr, Generics.Defaults,
  Generics.Collections, ASExecutionContext, Graphics, UITypes, GenHelpers,
  ASKernel, DoublePoint;

type
  [&Function('exprl')]
  [&Category(fcSystem)]
  FCN_ListExprNode = class(TASListExprNode);

  [&Function('identity')]
  [&Category(fcGeneral, fcMath)]
  FCN_Identity = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('add')]
  [&Category(fcGeneral, fcMath, fcStrings, fcSounds)]
  FCN_Add = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('subtract')]
  [&Category(fcGeneral, fcMath, fcSounds)]
  FCN_Subtract = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('negative')]
  [&Category(fcGeneral, fcMath)]
  FCN_UnaryMinus = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('multiply')]
  [&Category(fcGeneral, fcMath, fcStrings, fcSounds)]
  FCN_Multiply = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('InnerProduct')]
  [&Category(fcMath)]
  FCN_InnerProduct = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('divide')]
  [&Category(fcGeneral, fcMath)]
  FCN_Divide = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('power')]
  [&Category(fcMath)]
  FCN_Power = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('cross')]
  [&Category(fcMath)]
  FCN_Cross = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('CrossProduct')]
  [&Category(fcMath)]
  FCN_CrossProduct = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('angle', '∠')]
  [&Category(fcMath)]
  FCN_Angle = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('factorial')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_Factorial = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('abs')]
  [&Category(fcMath)]
  FCN_Absolute = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ConjugateTranspose')]
  [&Category(fcMath)]
  FCN_ConjugateTranspose = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('transpose')]
  [&Category(fcMath)]
  FCN_Transpose = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('arg')]
  [&Category(fcMath)]
  FCN_Argument = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Re')]
  [&Category(fcMath)]
  FCN_RealPart = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Im')]
  [&Category(fcMath)]
  FCN_ImaginaryPart = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('sqrt')]
  [&Category(fcMath)]
  FCN_Sqrt = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('degrees')]
  [&Category(fcMath)]
  FCN_Deg = class(TASSimpleFunction)
  strict private
    class var PiDiv180: TAlgosimNumber;
    class constructor ClassCreate;
    class destructor ClassDestroy;
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('percent')]
  [&Category(fcMath)]
  FCN_Percent = class(TASSimpleFunction)
  strict private
    class var OneHundredth: TAlgosimNumber;
    class constructor ClassCreate;
    class destructor ClassDestroy;
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('permille')]
  [&Category(fcMath)]
  FCN_Permille = class(TASSimpleFunction)
  strict private
    class var OneThousandth: TAlgosimNumber;
    class constructor ClassCreate;
    class destructor ClassDestroy;
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('square', 'sqr')]
  [&Category(fcMath)]
  FCN_Square = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('sin')]
  [&Category(fcMath, fcTrigonometry)]
  FCN_sin = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('cos')]
  [&Category(fcMath, fcTrigonometry)]
  FCN_cos = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('tan')]
  [&Category(fcMath, fcTrigonometry)]
  FCN_tan = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('cot')]
  [&Category(fcMath, fcTrigonometry)]
  FCN_cot = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('sec')]
  [&Category(fcMath, fcTrigonometry)]
  FCN_sec = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('csc')]
  [&Category(fcMath, fcTrigonometry)]
  FCN_csc = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('arcsin')]
  [&Category(fcMath, fcTrigonometry)]
  FCN_arcsin = class(TASSimpleFunctionNumDom)
  public
    procedure InitNode; override;
  end;

  [&Function('arccos')]
  [&Category(fcMath, fcTrigonometry)]
  FCN_arccos = class(TASSimpleFunctionNumDom)
  public
    procedure InitNode; override;
  end;

  [&Function('arctan')]
  [&Category(fcMath, fcTrigonometry)]
  FCN_arctan = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('arccot')]
  [&Category(fcMath, fcTrigonometry)]
  FCN_arccot = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('arcsec')]
  [&Category(fcMath, fcTrigonometry)]
  FCN_arcsec = class(TASSimpleFunctionNumDom)
  public
    procedure InitNode; override;
  end;

  [&Function('arccsc')]
  [&Category(fcMath, fcTrigonometry)]
  FCN_arccsc = class(TASSimpleFunctionNumDom)
  public
    procedure InitNode; override;
  end;

  [&Function('sinh')]
  [&Category(fcMath, fcHyperbolic)]
  FCN_sinh = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('cosh')]
  [&Category(fcMath, fcHyperbolic)]
  FCN_cosh = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('tanh')]
  [&Category(fcMath, fcHyperbolic)]
  FCN_tanh = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('coth')]
  [&Category(fcMath, fcHyperbolic)]
  FCN_coth = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('sech')]
  [&Category(fcMath, fcHyperbolic)]
  FCN_sech = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('csch')]
  [&Category(fcMath, fcHyperbolic)]
  FCN_csch = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('arcsinh')]
  [&Category(fcMath, fcHyperbolic)]
  FCN_arcsinh = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('arccosh')]
  [&Category(fcMath, fcHyperbolic)]
  FCN_arccosh = class(TASSimpleFunctionNumDom)
  public
    procedure InitNode; override;
  end;

  [&Function('arctanh')]
  [&Category(fcMath, fcHyperbolic)]
  FCN_arctanh = class(TASSimpleFunctionNumDom)
  public
    procedure InitNode; override;
  end;

  [&Function('arccoth')]
  [&Category(fcMath, fcHyperbolic)]
  FCN_arccoth = class(TASSimpleFunctionNumDom)
  public
    procedure InitNode; override;
  end;

  [&Function('arcsech')]
  [&Category(fcMath, fcHyperbolic)]
  FCN_arcsech = class(TASSimpleFunctionNumDom)
  public
    procedure InitNode; override;
  end;

  [&Function('arccsch')]
  [&Category(fcMath, fcHyperbolic)]
  FCN_arccsch = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('sinc')]
  [&Category(fcMath)]
  FCN_sinc = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('exp')]
  [&Category(fcMath)]
  FCN_exp = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('ln')]
  [&Category(fcMath)]
  FCN_ln = class(TASSimpleFunctionNumDom)
  public
    procedure InitNode; override;
  end;

  [&Function('log')]
  [&Category(fcMath)]
  FCN_log = class(TASSimpleFunctionNumDom)
  public
    procedure InitNode; override;
  end;

  [&Function('floor')]
  [&Category(fcMath)]
  FCN_Floor = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ceil')]
  [&Category(fcMath)]
  FCN_Ceil = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('round')]
  [&Category(fcMath)]
  FCN_Round = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('trunc')]
  [&Category(fcMath)]
  FCN_Trunc = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('frac')]
  [&Category(fcMath)]
  FCN_Frac = class(TASSimpleFunctionReal)
  public
    procedure InitNode; override;
  end;

  [&Function('sgn')]
  [&Category(fcMath)]
  FCN_Sgn = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('mod')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_mod = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('lcm')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_lcm = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('gcd')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_gcd = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('combinations', 'binomial')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_combinations = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('permutations')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_permutations = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsPrime')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_IsPrime = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('NextPrime')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_NextPrime = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('PrevPrime')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_PrevPrime = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('prime')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_NthPrime = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('PrimePi')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_PrimePi = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Fibonacci')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_Fibonacci = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Lucas')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_Lucas = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('MöbiusMu')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_MöbiusMu = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Mertens')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_Mertens = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('coprime')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_AreCoprime = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Iverson')]
  [&Category(fcMath)]
  FCN_Iverson = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Kronecker')]
  [&Category(fcMath)]
  FCN_Kronecker = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('LegendreSymbol')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_LegendreSymbol = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('JacobiSymbol')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_JacobiSymbol = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('KroneckerSymbol')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_KroneckerSymbol = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('totient')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_totient = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('cototient')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_cototient = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('PrimeFactors')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_PrimeFactors = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('rad')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_Radical = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsSquareFree')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_IsSquareFree = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('factors')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_Factorize = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FactorizedExpression')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_FactorizedExpression = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('divisors')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_Divisors = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ContinuedFraction')]
  [&Category(fcMath)]
  FCN_ContinuedFraction = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ToFraction')]
  [&Category(fcMath)]
  FCN_ToFraction = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ToSymbolicForm')]
  [&Category(fcMath)]
  FCN_ToSymbolicForm = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('erf')]
  [&Category(fcMath)]
  FCN_erf = class(TASSimpleFunctionReal)
  public
    procedure InitNode; override;
  end;

  [&Function('erfc')]
  [&Category(fcMath)]
  FCN_erfc = class(TASSimpleFunctionReal)
  public
    procedure InitNode; override;
  end;

  [&Function('FresnelC')]
  [&Category(fcMath)]
  FCN_FresnelC = class(TASSimpleFunctionReal)
  public
    procedure InitNode; override;
  end;

  [&Function('FresnelS')]
  [&Category(fcMath)]
  FCN_FresnelS = class(TASSimpleFunctionReal)
  public
    procedure InitNode; override;
  end;

  [&Function('Si')]
  [&Category(fcMath)]
  FCN_Si = class(TASSimpleFunctionReal)
  public
    procedure InitNode; override;
  end;

  [&Function('Ci')]
  [&Category(fcMath)]
  FCN_Ci = class(TASSimpleFunctionReal)
  public
    procedure InitNode; override;
  end;

  [&Function('Bessel')]
  [&Category(fcMath)]
  FCN_Bessel = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Laguerre')]
  [&Category(fcMath)]
  FCN_Laguerre = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Hermite')]
  [&Category(fcMath)]
  FCN_Hermite = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Legendre')]
  [&Category(fcMath)]
  FCN_Legendre = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('gamma')]
  [&Category(fcMath)]
  FCN_GammaFunction = class(TASSimpleFunctionNum)
  public
    procedure InitNode; override;
  end;

  [&Function('Chebyshev')]
  [&Category(fcMath)]
  FCN_Chebyshev = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Bernstein')]
  [&Category(fcMath)]
  FCN_Bernstein = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('HarmonicNumber')]
  [&Category(fcMath)]
  FCN_HarmonicNumber = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('and')]
  [&Category(fcLogic)]
  FCN_And = class(TASFunction)
  protected
    procedure DoExecute; override;
    procedure DoBitwise;
  end;

  [&Function('or')]
  [&Category(fcLogic)]
  FCN_Or = class(TASFunction)
  protected
    procedure DoExecute; override;
    procedure DoBitwise;
  end;

  [&Function('not')]
  [&Category(fcLogic)]
  FCN_Not = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('xor')]
  [&Category(fcLogic)]
  FCN_Xor = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('nand')]
  [&Category(fcLogic)]
  FCN_Nand = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('nor')]
  [&Category(fcLogic)]
  FCN_Nor = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ImpliesRight')]
  [&Category(fcLogic)]
  FCN_ImpliesRight = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ImpliesLeft')]
  [&Category(fcLogic)]
  FCN_ImpliesLeft = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('equivalent')]
  [&Category(fcLogic)]
  FCN_Equivalent = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('equals')]
  [&Category(fcGeneral)]
  FCN_Equals = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('NotEquals')]
  [&Category(fcGeneral)]
  FCN_NotEquals = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('LessThan')]
  [&Category(fcMath)]
  FCN_LessThan = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('LessThanOrEqualTo')]
  [&Category(fcMath)]
  FCN_LessThanOrEqualTo = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('GreaterThan')]
  [&Category(fcMath)]
  FCN_GreaterThan = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('GreaterThanOrEqualTo')]
  [&Category(fcMath)]
  FCN_GreaterThanOrEqualTo = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('dim')]
  [&Category(fcMath)]
  FCN_Dim = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('size')]
  [&Category(fcMath, fcTables, fcPixmaps)]
  FCN_Size = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('width')]
  [&Category(fcMath, fcTables, fcPixmaps)]
  FCN_Width = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('height')]
  [&Category(fcMath, fcTables, fcPixmaps)]
  FCN_Height = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('subscript')]
  [&Category(fcGeneral)]
  FCN_Subscript = class(TASFunction)
  strict private
    // An array (typically of integers) (when necessary) populated with copies
    // of the values of the child nodes to allow indices as direct children. For
    // instance, A[1, 2] is effectively translated into A['(1, 2)], where
    // '(1, 2) is stored in this array. All code executed later on will only use
    // the array form of the indices.
    FEquivArray: TAlgosimArray;
  protected
    procedure DoExecute; override;
  public
    function BuildLValue(LValueData: TLValueData): Boolean; override;
    function LValuePart: Boolean; override;
    destructor Destroy; override;
  end;

  FCN_AccessMember = class(TASFunction)
  protected
    procedure DoExecute; override;
  public
    function BuildLValue(LValueData: TLValueData): Boolean; override;
    function LValuePart: Boolean; override;
  end;

  [&Function('norm')]
  [&Category(fcMath)]
  FCN_Norm = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('NormSquared')]
  [&Category(fcMath)]
  FCN_NormSquared = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('normalized')]
  [&Category(fcMath)]
  FCN_Normalized = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('first')]
  [&Category(fcGeneral, fcLists, fcStrings)]
  FCN_First = class(TASFunction)
  protected
    procedure DoExecute; override;
  public
    function BuildLValue(LValueData: TLValueData): Boolean; override;
    function LValuePart: Boolean; override;
  end;

  [&Function('last')]
  [&Category(fcGeneral, fcLists, fcStrings)]
  FCN_Last = class(TASFunction)
  protected
    procedure DoExecute; override;
  public
    function BuildLValue(LValueData: TLValueData): Boolean; override;
    function LValuePart: Boolean; override;
  end;

  [&Function('part')]
  [&Category(fcGeneral, fcLists, fcStrings)]
  FCN_Part = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('range')]
  [&Category(fcGeneral, fcLists, fcStrings)]
  FCN_Range = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('sort')]
  [&Category(fcGeneral, fcLists)]
  FCN_Sort = class(TASSimpleFunction)
  private
    rcmp: IComparer<TASR>;
    ccmp: IComparer<TASC>;
    procedure ChooseComparer(const AStr: string);
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('CustomSort')]
  [&Category(fcGeneral, fcLists)]
  FCN_CustomSort = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('shuffle')]
  [&Category(fcGeneral, fcLists, fcStrings, fcPixmaps)]
  FCN_Shuffle = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('reverse')]
  [&Category(fcGeneral, fcLists, fcStrings, fcSounds)]
  FCN_Reverse = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('unique', 'RemoveDuplicates')]
  [&Category(fcGeneral, fcLists)]
  FCN_Unique = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RemoveAdjacentDuplicates')]
  [&Category(fcGeneral, fcLists)]
  FCN_AdjUnique = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('frequencies')]
  [&Category(fcGeneral, fcLists)]
  FCN_Frequencies = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('collapse')]
  [&Category(fcLists)]
  FCN_CollapseSequences = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ZeroVector')]
  [&Category(fcMath)]
  FCN_ZeroVector = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ComplexZeroVector')]
  [&Category(fcMath)]
  FCN_ComplexZeroVector = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RandomVector')]
  [&Category(fcMath)]
  FCN_RandomVector = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RandomIntVector')]
  [&Category(fcMath)]
  FCN_RandomIntVector = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RandomSignedVector')]
  [&Category(fcMath)]
  FCN_RandomSignedVector = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('BasisVector')]
  [&Category(fcMath)]
  FCN_BasisVector = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SequenceVector')]
  [&Category(fcMath)]
  FCN_SequenceVector = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SequenceList')]
  [&Category(fcMath)]
  FCN_SequenceList = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  TIntervalFunction = class(TASSimpleFunction)
  protected
    OpenInterval: Boolean;
    procedure SimpleFunction; override;
  end;  

  [&Function('ClosedInterval', 'interval')]
  [&Category(fcMath)]
  FCN_ClosedInterval = class(TIntervalFunction)
  protected
    procedure InitNode; override;
  end;

  [&Function('OpenInterval')]
  [&Category(fcMath)]
  FCN_OpenInterval = class(TIntervalFunction)
  protected
    procedure InitNode; override;  
  end;  

  [&Function('random')]
  [&Category(fcGeneral)]
  FCN_Random = class(TASFunction)
  protected
    procedure DoExecute; override;
  public
    function BuildLValue(LValueData: TLValueData): Boolean; override;
    function LValuePart: Boolean; override;
  end;

  [&Function('RandomInt')]
  [&Category(fcMath)]
  FCN_RandomInt = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RandomReal')]
  [&Category(fcMath)]
  FCN_RandomReal = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SetRandomSeed')]
  [&Category(fcMath)]
  FCN_SetRandomSeed = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('randomize')]
  [&Category(fcGeneral)]
  FCN_Randomize = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  TASContainerFunction = class abstract(TASFunction)
  protected
    procedure fcn(AObject: TAlgosimObject); virtual; abstract;
    procedure DoExecute; override; final;
  end;

  [&Function('sum', '∑')]
  [&Category(fcMath)]
  FCN_Sum = class(TASContainerFunction)
  protected
    procedure fcn(AObject: TAlgosimObject); override;
  end;

  [&Function('product', '∏')]
  [&Category(fcMath)]
  FCN_Product = class(TASContainerFunction)
  protected
    procedure fcn(AObject: TAlgosimObject); override;
  end;

  [&Function('min')]
  [&Category(fcMath)]
  FCN_Min = class(TASContainerFunction)
  protected
    procedure fcn(AObject: TAlgosimObject); override;
  end;

  [&Function('max')]
  [&Category(fcMath)]
  FCN_Max = class(TASContainerFunction)
  protected
    procedure fcn(AObject: TAlgosimObject); override;
  end;

  [&Function('ArithmeticMean', 'mean', 'average')]
  [&Category(fcMath)]
  FCN_ArithmeticMean = class(TASContainerFunction)
  protected
    procedure fcn(AObject: TAlgosimObject); override;
  end;

  [&Function('GeometricMean')]
  [&Category(fcMath)]
  FCN_GeometricMean = class(TASContainerFunction)
  protected
    procedure fcn(AObject: TAlgosimObject); override;
  end;

  [&Function('HarmonicMean')]
  [&Category(fcMath)]
  FCN_HarmonicMean = class(TASContainerFunction)
  protected
    procedure fcn(AObject: TAlgosimObject); override;
  end;

  TASContainerPredicateFunction = class abstract(TASFunction)
  protected
    procedure fcn(AObject: TAlgosimObject; APred: TASOPredicate);
      virtual; abstract;
    procedure DoExecute; override;
  end;

  [&Function('count')]
  [&Category(fcGeneral, fcLists)]
  FCN_Count = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('contains')]
  [&Category(fcGeneral, fcLists)]
  FCN_Contains = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('exists', '∃')]
  [&Category(fcGeneral, fcLists)]
  FCN_Exists = class(TASContainerPredicateFunction)
  protected
    procedure fcn(AObject: TAlgosimObject;
      APred: TASOPredicate); override;
  end;

  [&Function('ExistsUnique')]
  [&Category(fcGeneral, fcLists)]
  FCN_ExistsUnique = class(TASContainerPredicateFunction)
  protected
    procedure fcn(AObject: TAlgosimObject;
      APred: TASOPredicate); override;
  end;

  [&Function('ForAll', '∀')]
  [&Category(fcGeneral, fcLists)]
  FCN_ForAll = class(TASContainerPredicateFunction)
  protected
    procedure fcn(AObject: TAlgosimObject;
      APred: TASOPredicate); override;
  end;

  [&Function('indices')]
  [&Category(fcGeneral, fcLists)]
  FCN_IndicesOf = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('filter')]
  [&Category(fcGeneral, fcLists)]
  FCN_Filter = class(TASContainerPredicateFunction)
  protected
    procedure fcn(AObject: TAlgosimObject;
      APred: TASOPredicate); override;
  end;

  [&Function('pick')]
  [&Category(fcGeneral, fcLists)]
  FCN_Pick = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('PickRecursive')]
  [&Category(fcGeneral, fcLists)]
  FCN_PickRecursive = class(TASContainerPredicateFunction)
  protected
    procedure fcn(AObject: TAlgosimObject;
      APred: TASOPredicate); override;
  end;

  [&Function('apply')]
  [&Category(fcGeneral, fcLists)]
  FCN_Apply = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ApplyIf')]
  [&Category(fcGeneral, fcLists)]
  FCN_ApplyIf = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ReplaceAll')]
  [&Category(fcGeneral, fcLists)]
  FCN_ReplaceAll = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ReplaceIf')]
  [&Category(fcGeneral, fcLists)]
  FCN_ReplaceIf = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ReplaceEvery')]
  [&Category(fcGeneral, fcLists)]
  FCN_ReplaceEvery = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RemoveAll')]
  [&Category(fcGeneral, fcLists)]
  FCN_RemoveAll = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RemoveIf')]
  [&Category(fcGeneral, fcLists)]
  FCN_RemoveIf = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RealNumber')]
  [&Category(fcGeneral)]
  FCN_RealNumber = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ComplexNumber')]
  [&Category(fcGeneral)]
  FCN_ComplexNumber = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('number')]
  [&Category(fcGeneral)]
  FCN_Number = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('integer')]
  [&Category(fcGeneral)]
  FCN_Integer = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('string')]
  [&Category(fcGeneral)]
  FCN_String = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RealVector')]
  [&Category(fcGeneral)]
  FCN_RealVector = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ComplexVector')]
  [&Category(fcGeneral)]
  FCN_ComplexVector = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('vector')]
  [&Category(fcGeneral, fcMath)]
  FCN_Vector = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RealMatrix')]
  [&Category(fcGeneral)]
  FCN_RealMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ComplexMatrix')]
  [&Category(fcGeneral)]
  FCN_ComplexMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('matrix')]
  [&Category(fcGeneral, fcMath)]
  FCN_Matrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('boolean')]
  [&Category(fcGeneral)]
  FCN_Boolean = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ToList')]
  [&Category(fcGeneral)]
  FCN_ToList = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ToSet')]
  [&Category(fcGeneral)]
  FCN_ToSet = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ToTable')]
  [&Category(fcGeneral)]
  FCN_ToTable = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('BinaryData')]
  [&Category(fcGeneral)]
  FCN_BinaryData = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('MatFromCols')]
  [&Category(fcGeneral, fcMath)]
  FCN_MatrixFromCols = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('MatFromRows')]
  [&Category(fcGeneral, fcMath)]
  FCN_MatrixFromRows = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('MatFromBlocks')]
  [&Category(fcGeneral, fcMath)]
  FCN_MatrixFromBlocks = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('list', '''')]
  [&Category(fcLists)]
  FCN_List = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('set')]
  [&Category(fcSets)]
  FCN_Set = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('union')]
  [&Category(fcSets)]
  FCN_Union = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('intersection')]
  [&Category(fcSets)]
  FCN_Intersection = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SetDifference')]
  [&Category(fcSets)]
  FCN_SetDifference = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SymmetricDifference')]
  [&Category(fcSets)]
  FCN_SymDiff = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('complement')]
  [&Category(fcSets)]
  FCN_Complement = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ElementOf')]
  [&Category(fcSets)]
  FCN_ElementOf = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('NotElementOf')]
  [&Category(fcSets)]
  FCN_NotElementOf = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ContainsAsElement')]
  [&Category(fcSets)]
  FCN_ContainsAsElement = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('NotContainsAsElement')]
  [&Category(fcSets)]
  FCN_NotContainsAsElement = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('subset')]
  [&Category(fcSets)]
  FCN_Subset = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ProperSubset')]
  [&Category(fcSets)]
  FCN_ProperSubset = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('superset')]
  [&Category(fcSets)]
  FCN_Superset = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ProperSuperset')]
  [&Category(fcSets)]
  FCN_ProperSuperset = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('type')]
  [&Category(fcSystem)]
  FCN_TypeName = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('ClassData')]
  [&Category(fcSystem)]
  FCN_ClassTypeData = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('class')]
  [&Category(fcSystem)]
  FCN_ClassTypeName = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('HasComplexType')]
  [&Category(fcSystem)]
  FCN_HasComplexType = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('IsObjectContainer')]
  [&Category(fcSystem)]
  FCN_IsObjectContainer = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('IsValueContainer')]
  [&Category(fcSystem)]
  FCN_IsValueContainer = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('IsPlanarContainer')]
  [&Category(fcSystem)]
  FCN_IsPlanarContainer = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('IsOrderedContainer')]
  [&Category(fcSystem)]
  FCN_IsOrderedContainer = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('beep')]
  [&Category(fcSystem)]
  FCN_Beep = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('wait', 'sleep')]
  [&Category(fcSystem)]
  FCN_Wait = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('TickCount')]
  [&Category(fcSystem)]
  FCN_GetTickCount = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Heaviside')]
  [&Category(fcMath)]
  FCN_Heaviside = class(TASSimpleFunctionReal)
  public
    procedure InitNode; override;
  end;

  [&Function('ramp')]
  [&Category(fcMath)]
  FCN_Ramp = class(TASSimpleFunctionReal)
  public
    procedure InitNode; override;
  end;

  [&Function('rect')]
  [&Category(fcMath)]
  FCN_Rect = class(TASSimpleFunctionReal)
  public
    procedure InitNode; override;
  end;

  [&Function('tri')]
  [&Category(fcMath)]
  FCN_Tri = class(TASSimpleFunctionReal)
  public
    procedure InitNode; override;
  end;

  [&Function('property')]
  [&Category(fcSystem)]
  FCN_GetProperty = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('integrate', '∫')]
  [&Category(fcMath)]
  FCN_Integrate = class abstract(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('differentiate', 'diff')]
  [&Category(fcMath)]
  FCN_Differentiate = class abstract(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('length', 'cardinality', 'card')]
  [&Category(fcGeneral, fcLists, fcStrings, fcStructures, fcSets)]
  FCN_Length = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('StringPos')]
  [&Category(fcStrings)]
  FCN_Pos = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('StringContains')]
  [&Category(fcStrings)]
  FCN_StringContains = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('StringCount')]
  [&Category(fcStrings)]
  FCN_SubstringCount = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('StringIndices')]
  [&Category(fcStrings)]
  FCN_SubstringIndices = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('StringReplace')]
  [&Category(fcStrings)]
  FCN_StringReplace = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('split')]
  [&Category(fcStrings)]
  FCN_Split = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('join')]
  [&Category(fcStrings)]
  FCN_Join = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('UpperCase')]
  [&Category(fcStrings)]
  FCN_UpperCase = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('LowerCase')]
  [&Category(fcStrings)]
  FCN_LowerCase = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('InvertCase')]
  [&Category(fcStrings)]
  FCN_InvertCase = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('TitleCase')]
  [&Category(fcStrings)]
  FCN_TitleCase = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SentenceCase')]
  [&Category(fcStrings)]
  FCN_SentenceCase = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('rot13')]
  [&Category(fcStrings)]
  FCN_ROT13 = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Caesar')]
  [&Category(fcStrings)]
  FCN_Caesar = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('VigenèreEncode')]
  [&Category(fcStrings)]
  FCN_Vigenère = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('VigenèreDecode')]
  [&Category(fcStrings)]
  FCN_VigenèreDecode = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('trim')]
  [&Category(fcStrings)]
  FCN_Trim = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('TrimLeft')]
  [&Category(fcStrings)]
  FCN_TrimLeft = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('TrimRight')]
  [&Category(fcStrings)]
  FCN_TrimRight = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('StringPad')]
  [&Category(fcStrings)]
  FCN_Pad = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('format')]
  [&Category(fcStrings)]
  FCN_Format = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('index')]
  [&Category(fcGeneral, fcLists, fcStructures)]
  FCN_IndexOf = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  TCharTestFunction = class abstract(TASSimpleFunction)
  protected
  type
    TChrTestFcn = function(C: char): Boolean;
  var
    fcn: TChrTestFcn;
    procedure SimpleFunction; override; final;
  end;

  [&Function('ChrIsLetter')]
  [&Category(fcStrings)]
  FCN_ChrIsLetter = class(TCharTestFunction)
  public
    procedure InitNode; override;
  end;

  [&Function('ChrIsDigit')]
  [&Category(fcStrings)]
  FCN_ChrIsDigit = class(TCharTestFunction)
  public
    procedure InitNode; override;
  end;

  [&Function('ChrIsLetterOrDigit')]
  [&Category(fcStrings)]
  FCN_ChrIsLetterOrDigit = class(TCharTestFunction)
  public
    procedure InitNode; override;
  end;

  [&Function('ChrIsNumber')]
  [&Category(fcStrings)]
  FCN_ChrIsNumber = class(TCharTestFunction)
  public
    procedure InitNode; override;
  end;

  [&Function('ChrIsPunctuation')]
  [&Category(fcStrings)]
  FCN_ChrIsPunctuation = class(TCharTestFunction)
  public
    procedure InitNode; override;
  end;

  [&Function('ChrIsSeparator')]
  [&Category(fcStrings)]
  FCN_ChrIsSeparator = class(TCharTestFunction)
  public
    procedure InitNode; override;
  end;

  [&Function('ChrIsWhitespace')]
  [&Category(fcStrings)]
  FCN_ChrIsWhitespace = class(TCharTestFunction)
  public
    procedure InitNode; override;
  end;

  [&Function('ChrIsUpperCase')]
  [&Category(fcStrings)]
  FCN_ChrIsUpperCase = class(TCharTestFunction)
  public
    procedure InitNode; override;
  end;

  [&Function('ChrIsLowerCase')]
  [&Category(fcStrings)]
  FCN_ChrIsLowerCase = class(TCharTestFunction)
  public
    procedure InitNode; override;
  end;

  [&Function('ChrIsSymbol')]
  [&Category(fcStrings)]
  FCN_ChrIsSymbol = class(TCharTestFunction)
  public
    procedure InitNode; override;
  end;

  [&Function('ChrIsASCII')]
  [&Category(fcStrings)]
  FCN_ChrIsASCII = class(TCharTestFunction)
  strict private
    class function IsASCII(C: char): Boolean; static; inline;
  public
    procedure InitNode; override;
  end;

  [&Function('ChrIsControl')]
  [&Category(fcStrings)]
  FCN_ChrIsControl = class(TCharTestFunction)
  public
    procedure InitNode; override;
  end;

  [&Function('ChrName')]
  [&Category(fcStrings)]
  FCN_ChrName = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ChrBlock')]
  [&Category(fcStrings)]
  FCN_ChrBlock = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ChrBlocks')]
  [&Category(fcStrings)]
  FCN_ListChrBlocks = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ChrBlockRange')]
  [&Category(fcStrings)]
  FCN_ChrBlockRange = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('chr')]
  [&Category(fcStrings)]
  FCN_Character = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ord')]
  [&Category(fcStrings)]
  FCN_ChrCode = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ChrNumVal')]
  [&Category(fcStrings)]
  FCN_ChrNumVal = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('odd')]
  [&Category(fcMath)]
  FCN_Odd = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('even')]
  [&Category(fcMath)]
  FCN_Even = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('date')]
  [&Category(fcDateTime)]
  FCN_Date = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('time')]
  [&Category(fcDateTime)]
  FCN_Time = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('now')]
  [&Category(fcDateTime)]
  FCN_Now = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('datetime')]
  [&Category(fcDateTime)]
  FCN_DateTime = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  TTimeOneParamFcn = class abstract(TASSimpleFunction)
  protected
    type
      TTimeOneParamFcn32 = function(const ADateTime: TDateTime; const AParam: Integer): TDateTime;
      TTimeOneParamFcn64 = function(const ADateTime: TDateTime; const AParam: Int64): TDateTime;
    var
      fcn32: TTimeOneParamFcn32;
      fcn64: TTimeOneParamFcn64;

    procedure SimpleFunction; override; final;
  end;

  [&Function('AddMilliseconds')]
  [&Category(fcDateTime)]
  FCN_AddMilliseconds = class(TTimeOneParamFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('AddSeconds')]
  [&Category(fcDateTime)]
  FCN_AddSeconds = class(TTimeOneParamFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('AddMinutes')]
  [&Category(fcDateTime)]
  FCN_AddMinutes = class(TTimeOneParamFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('AddHours')]
  [&Category(fcDateTime)]
  FCN_AddHours = class(TTimeOneParamFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('AddDays')]
  [&Category(fcDateTime)]
  FCN_AddDays = class(TTimeOneParamFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('AddWeeks')]
  [&Category(fcDateTime)]
  FCN_AddWeeks = class(TTimeOneParamFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('AddMonths')]
  [&Category(fcDateTime)]
  FCN_AddMonths = class(TTimeOneParamFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('AddYears')]
  [&Category(fcDateTime)]
  FCN_AddYears = class(TTimeOneParamFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('IsValidDate')]
  [&Category(fcDateTime)]
  FCN_DateValid = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsValidTime')]
  [&Category(fcDateTime)]
  FCN_TimeValid = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsValidDatetime')]
  [&Category(fcDateTime)]
  FCN_DateTimeValid = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  TTimeTimeDoubleFcn = class abstract(TASSimpleFunction)
  protected
    type
      _TTimeTimeDoubleFcn = function(const ATime1, ATime2: TDateTime): double;
    var
      fcn: _TTimeTimeDoubleFcn;

    procedure SimpleFunction; override; final;
  end;

  [&Function('MillisecondsBetween')]
  [&Category(fcDateTime)]
  FCN_MillisecondsBetween = class(TTimeTimeDoubleFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('SecondsBetween')]
  [&Category(fcDateTime)]
  FCN_SecondsBetween = class(TTimeTimeDoubleFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('MinutesBetween')]
  [&Category(fcDateTime)]
  FCN_MinutesBetween = class(TTimeTimeDoubleFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('HoursBetween')]
  [&Category(fcDateTime)]
  FCN_HoursBetween = class(TTimeTimeDoubleFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('DaysBetween')]
  [&Category(fcDateTime)]
  FCN_DaysBetween = class(TTimeTimeDoubleFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('WeeksBetween')]
  [&Category(fcDateTime)]
  FCN_WeeksBetween = class(TTimeTimeDoubleFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('MonthsBetween')]
  [&Category(fcDateTime)]
  FCN_MonthsBetween = class(TTimeTimeDoubleFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('YearsBetween')]
  [&Category(fcDateTime)]
  FCN_YearsBetween = class(TTimeTimeDoubleFcn)
  public
    procedure InitNode; override;
  end;

  TTimeIntFcn = class abstract(TASSimpleFunction)
  protected
    type
      TTimeIntFcn16 = function(const ADateTime: TDateTime): Word;
      TTimeIntFcn32 = function(const ADateTime: TDateTime): Cardinal;
      TTimeIntFcn64 = function(const ADateTime: TDateTime): Int64;
    var
      fcn16: TTimeIntFcn16;
      fcn32: TTimeIntFcn32;
      fcn64: TTimeIntFcn64;
      IntFmt: TFormatStyle;

    procedure SimpleFunction; override;
  end;

  [&Function('DayOfTheWeek')]
  [&Category(fcDateTime)]
  FCN_DayOfTheWeek = class(TTimeIntFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('DayOfTheMonth')]
  [&Category(fcDateTime)]
  FCN_DayOfTheMonth = class(TTimeIntFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('DayOfTheYear')]
  [&Category(fcDateTime)]
  FCN_DayOfTheYear = class(TTimeIntFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('WeekOfTheYear')]
  [&Category(fcDateTime)]
  FCN_WeekOfTheYear = class(TTimeIntFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('SecondOfTheDay')]
  [&Category(fcDateTime)]
  FCN_SecondOfTheDay = class(TTimeIntFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('SecondOfTheWeek')]
  [&Category(fcDateTime)]
  FCN_SecondOfTheWeek = class(TTimeIntFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('SecondOfTheMonth')]
  [&Category(fcDateTime)]
  FCN_SecondOfTheMonth = class(TTimeIntFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('SecondOfTheYear')]
  [&Category(fcDateTime)]
  FCN_SecondOfTheYear = class(TTimeIntFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('MillisecondOfTheDay')]
  [&Category(fcDateTime)]
  FCN_MillisecondOfTheDay = class(TTimeIntFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('MillisecondOfTheWeek')]
  [&Category(fcDateTime)]
  FCN_MillisecondOfTheWeek = class(TTimeIntFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('MillisecondOfTheMonth')]
  [&Category(fcDateTime)]
  FCN_MillisecondOfTheMonth = class(TTimeIntFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('MillisecondOfTheYear')]
  [&Category(fcDateTime)]
  FCN_MillisecondOfTheYear = class(TTimeIntFcn)
  public
    procedure InitNode; override;
  end;

  [&Function('IsLeapYear')]
  [&Category(fcDateTime)]
  FCN_IsLeapYear = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DaysInYear')]
  [&Category(fcDateTime)]
  FCN_DaysInYear = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DaysInMonth')]
  [&Category(fcDateTime)]
  FCN_DaysInMonth = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('timestamp')]
  [&Category(fcDateTime)]
  FCN_Timestamp = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('today')]
  [&Category(fcDateTime)]
  FCN_Today = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('tomorrow')]
  [&Category(fcDateTime)]
  FCN_Tomorrow = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('yesterday')]
  [&Category(fcDateTime)]
  FCN_Yesterday = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('TruncToMillisecond')]
  [&Category(fcDateTime)]
  FCN_TruncateToMillisecond = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('TruncToSecond')]
  [&Category(fcDateTime)]
  FCN_TruncateToSecond = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('TruncToMinute')]
  [&Category(fcDateTime)]
  FCN_TruncateToMinute = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('TruncToHour')]
  [&Category(fcDateTime)]
  FCN_TruncateToHour = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('TruncToDay')]
  [&Category(fcDateTime)]
  FCN_TruncateToDay = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('TruncToMonth')]
  [&Category(fcDateTime)]
  FCN_TruncateToMonth = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('TruncToYear')]
  [&Category(fcDateTime)]
  FCN_TruncateToYear = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('NumDigits')]
  [&Category(fcSystem)]
  FCN_NumDigits = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('MinLength')]
  [&Category(fcSystem)]
  FCN_MinLength = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('NumberFormat')]
  [&Category(fcSystem)]
  FCN_NumberFormat = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('NumberBase')]
  [&Category(fcSystem)]
  FCN_NumberBase = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('FormatStyle')]
  [&Category(fcSystem)]
  FCN_FormatStyle = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('DigitGrouping')]
  [&Category(fcSystem)]
  FCN_DigitGrouping = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('PrettyExp')]
  [&Category(fcSystem)]
  FCN_PrettyExp = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('MaxLen')]
  [&Category(fcSystem)]
  FCN_MaxLen = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('SetNumDigits')]
  [&Category(fcSystem)]
  FCN_SetNumDigits = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SetMinLength')]
  [&Category(fcSystem)]
  FCN_SetMinLength = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SetNumberFormat')]
  [&Category(fcSystem)]
  FCN_SetNumberFormat = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SetNumberBase')]
  [&Category(fcSystem)]
  FCN_SetNumberBase = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SetFormatStyle')]
  [&Category(fcSystem)]
  FCN_SetFormatStyle = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SetDigitGrouping')]
  [&Category(fcSystem)]
  FCN_SetDigitGrouping = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SetPrettyExp')]
  [&Category(fcSystem)]
  FCN_SetPrettyExp = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SetMaxLen')]
  [&Category(fcSystem)]
  FCN_SetMaxLen = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AsSingleLine')]
  [&Category(fcSystem)]
  FCN_AsSingleLine = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('InputForm')]
  [&Category(fcSystem)]
  FCN_InputForm = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('AsMultiLine')]
  [&Category(fcSystem)]
  FCN_AsMultiLine = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('SaveToFile', 'export')]
  [&Category(fcSystem)]
  FCN_SaveToFile = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('LoadFromFile')]
  [&Category(fcSystem)]
  FCN_LoadFromFile = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('CopyToClipboard')]
  [&Category(fcSystem)]
  FCN_CopyToClipboard = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('flatten')]
  [&Category(fcLists)]
  FCN_Flatten = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('group')]
  [&Category(fcLists)]
  FCN_Group = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  TSymbolNameFcn = class(TASFunction)
  protected
    procedure DoExecute; override; final;
    procedure fcn(const ASymbolName: string); virtual; abstract;
  end;

  [&Function('variable')]
  [&Category(fcSystem)]
  FCN_Variable = class(TSymbolNameFcn)
  protected
    procedure fcn(const ASymbolName: string); override;
  end;

  [&Function('object')]
  [&Category(fcSystem)]
  FCN_Object = class(TSymbolNameFcn)
  protected
    procedure fcn(const ASymbolName: string); override;
  end;

  [&Function('metadata')]
  [&Category(fcSystem)]
  FCN_Metadata = class(TSymbolNameFcn)
  protected
    procedure fcn(const ASymbolName: string); override;
  end;

  [&Function('description')]
  [&Category(fcSystem)]
  FCN_Description = class(TSymbolNameFcn)
  protected
    procedure fcn(const ASymbolName: string); override;
  end;

  [&Function('delete')]
  [&Category(fcSystem)]
  FCN_Delete = class(TSymbolNameFcn)
  protected
    procedure fcn(const ASymbolName: string); override;
  end;

  [&Function('protect')]
  [&Category(fcSystem)]
  FCN_Protect = class(TSymbolNameFcn)
  protected
    procedure fcn(const ASymbolName: string); override;
  end;

  [&Function('unprotect')]
  [&Category(fcSystem)]
  FCN_Unprotect = class(TSymbolNameFcn)
  protected
    procedure fcn(const ASymbolName: string); override;
  end;

  [&Function('assign')]
  [&Category(fcSystem)]
  FCN_Assign = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('cls')]
  [&Category(fcSystem)]
  FCN_Cls = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('exit')]
  [&Category(fcSystem)]
  FCN_Exit = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('error', 'fail')]
  [&Category(fcSystem)]
  FCN_Fail = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('assert')]
  [&Category(fcSystem)]
  FCN_Assert = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('succeeded')]
  [&Category(fcSystem)]
  FCN_Succeeded = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('try')]
  [&Category(fcSystem)]
  FCN_Try = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('piecewise')]
  [&Category(fcMath)]
  FCN_Piecewise = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('MakeMember')]
  [&Category(fcStructures)]
  FCN_MakeMember = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('struct', 'structure')]
  [&Category(fcStructures)]
  FCN_MakeStruct = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('system')]
  [&Category(fcSystem)]
  FCN_System = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RotLeft')]
  [&Category(fcGeneral)]
  FCN_RotLeft = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RotRight')]
  [&Category(fcGeneral)]
  FCN_RotRight = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('diag')]
  [&Category(fcMath)]
  FCN_Diag = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('row')]
  [&Category(fcGeneral, fcMath, fcTables)]
  FCN_Row = class(TASFunction)
  protected
    procedure DoExecute; override;
  public
    function BuildLValue(LValueData: TLValueData): Boolean; override;
    function LValuePart: Boolean; override;
  end;

  [&Function('col')]
  [&Category(fcGeneral, fcMath, fcTables)]
  FCN_Col = class(TASFunction)
  protected
    procedure DoExecute; override;
  public
    function BuildLValue(LValueData: TLValueData): Boolean; override;
    function LValuePart: Boolean; override;
  end;

  [&Function('rows')]
  [&Category(fcGeneral, fcMath, fcTables)]
  FCN_Rows = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('cols')]
  [&Category(fcGeneral, fcMath, fcTables)]
  FCN_Cols = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('MainDiagonal')]
  [&Category(fcMath)]
  FCN_MainDiagonal = class(TASFunction)
  protected
    procedure DoExecute; override;
  public
    function BuildLValue(LValueData: TLValueData): Boolean; override;
    function LValuePart: Boolean; override;
  end;

  [&Function('superdiagonal')]
  [&Category(fcMath)]
  FCN_Superdiagonal = class(TASFunction)
  protected
    procedure DoExecute; override;
  public
    function BuildLValue(LValueData: TLValueData): Boolean; override;
    function LValuePart: Boolean; override;
  end;

  [&Function('subdiagonal')]
  [&Category(fcMath)]
  FCN_Subdiagonal = class(TASFunction)
  protected
    procedure DoExecute; override;
  public
    function BuildLValue(LValueData: TLValueData): Boolean; override;
    function LValuePart: Boolean; override;
  end;

  [&Function('antidiagonal')]
  [&Category(fcMath)]
  FCN_Antidiagonal = class(TASFunction)
  protected
    procedure DoExecute; override;
  public
    function BuildLValue(LValueData: TLValueData): Boolean; override;
    function LValuePart: Boolean; override;
  end;

  [&Function('ReplaceRow')]
  [&Category(fcMath)]
  FCN_ReplaceRow = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ReplaceCol')]
  [&Category(fcMath)]
  FCN_ReplaceCol = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ReplaceDiagonal')]
  [&Category(fcMath)]
  FCN_ReplaceDiagonal = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ReplaceSuperdiagonal')]
  [&Category(fcMath)]
  FCN_ReplaceSuperdiagonal = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ReplaceSubdiagonal')]
  [&Category(fcMath)]
  FCN_ReplaceSubdiagonal = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ReplaceAntidiagonal')]
  [&Category(fcMath)]
  FCN_ReplaceAntidiagonal = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsRow')]
  [&Category(fcGeneral, fcMath, fcPixmaps, fcTables)]
  FCN_IsRow = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('IsCol')]
  [&Category(fcGeneral, fcMath, fcPixmaps, fcTables)]
  FCN_IsCol = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('IsSquare')]
  [&Category(fcGeneral, fcMath, fcPixmaps, fcTables)]
  FCN_IsSquare = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  TMatrixEpsilonFunction<T> = class abstract(TASFunction)
  strict protected
    type
      TEpsilonFcn = function(const Epsilon: Extended = 0): T of object;
    var
      rfcn, cfcn: TEpsilonFcn;
      generic_result: T;
    class var
      _TRealMatrix: TRealMatrix; // only used in child classes to get method code ptrs in a semi-type-safe manner
      _TComplexMatrix: TComplexMatrix;
  protected
    procedure DoExecute; override;
  end;

  TMatrixQueryWithEpsilon = class abstract(TMatrixEpsilonFunction<Boolean>)
  protected
    procedure DoExecute; override;
  end;

  [&Function('IsIdentity')]
  [&Category(fcMath)]
  FCN_IsIdentity = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsZeroMatrix')]
  [&Category(fcMath)]
  FCN_IsZeroMatrix = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsDiagonal')]
  [&Category(fcMath)]
  FCN_IsDiagonal = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsAntidiagonal')]
  [&Category(fcMath)]
  FCN_IsAntiDiagonal = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsReversal')]
  [&Category(fcMath)]
  FCN_IsReversal = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsUpperTriangular')]
  [&Category(fcMath)]
  FCN_IsUpperTriangular = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsLowerTriangular')]
  [&Category(fcMath)]
  FCN_IsLowerTriangular = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsTriangular')]
  [&Category(fcMath)]
  FCN_IsTriangular = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsRowEchelonForm')]
  [&Category(fcMath)]
  FCN_IsRowEchelonForm = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsReducedRowEchelonForm')]
  [&Category(fcMath)]
  FCN_IsReducedRowEchelonForm = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsScalar')]
  [&Category(fcMath)]
  FCN_IsScalar = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsSymmetric')]
  [&Category(fcMath)]
  FCN_IsSymmetric = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsSkewSymmetric')]
  [&Category(fcMath)]
  FCN_IsSkewSymmetric = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsHermitian', 'IsSelfAdjoint')]
  [&Category(fcMath)]
  FCN_IsHermitian = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsSkewHermitian')]
  [&Category(fcMath)]
  FCN_IsSkewHermitian = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsOrthogonal')]
  [&Category(fcMath)]
  FCN_IsOrthogonal = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsUnitary')]
  [&Category(fcMath)]
  FCN_IsUnitary = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsNormal')]
  [&Category(fcMath)]
  FCN_IsNormal = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsBinary')]
  [&Category(fcMath)]
  FCN_IsBinary = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsPermutation')]
  [&Category(fcMath)]
  FCN_IsPermutation = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsCirculant')]
  [&Category(fcMath)]
  FCN_IsCirculant = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsToeplitz')]
  [&Category(fcMath)]
  FCN_IsToeplitz = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsHankel')]
  [&Category(fcMath)]
  FCN_IsHankel = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsUpperHessenberg')]
  [&Category(fcMath)]
  FCN_IsUpperHessenberg = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsLowerHessenberg')]
  [&Category(fcMath)]
  FCN_IsLowerHessenberg = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsTridiagonal')]
  [&Category(fcMath)]
  FCN_IsTridiagonal = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsUpperBidiagonal')]
  [&Category(fcMath)]
  FCN_IsUpperBidiagonal = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsLowerBidiagonal')]
  [&Category(fcMath)]
  FCN_IsLowerBidiagonal = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsBidiagonal')]
  [&Category(fcMath)]
  FCN_IsBidiagonal = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsCentrosymmetric')]
  [&Category(fcMath)]
  FCN_IsCentrosymmetric = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsVandermonde')]
  [&Category(fcMath)]
  FCN_IsVandermonde = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsIdempotent')]
  [&Category(fcMath)]
  FCN_IsIdempotent = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsInvolution')]
  [&Category(fcMath)]
  FCN_IsInvolution = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsPositiveDefinite')]
  [&Category(fcMath)]
  FCN_IsPositiveDefinite = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsPositiveSemidefinite')]
  [&Category(fcMath)]
  FCN_IsPositiveSemidefinite = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsNegativeDefinite')]
  [&Category(fcMath)]
  FCN_IsNegativeDefinite = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsNegativeSemidefinite')]
  [&Category(fcMath)]
  FCN_IsNegativeSemidefinite = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsIndefinite')]
  [&Category(fcMath)]
  FCN_IsIndefinite = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  [&Function('IsNilpotent')]
  [&Category(fcMath)]
  FCN_IsNilpotent = class(TMatrixQueryWithEpsilon)
    procedure InitNode; override;
  end;

  TMatrixIntFcnWithEpsilon = class abstract(TMatrixEpsilonFunction<Integer>)
  protected
    procedure DoExecute; override;
  end;

  [&Function('NilpotencyIndex')]
  [&Category(fcMath)]
  FCN_NilpotencyIndex = class(TMatrixIntFcnWithEpsilon)
  protected
    procedure InitNode; override;
  end;

  TNumEntEpsilonFunction = class abstract(TASFunction)
  protected
    procedure fcn(AObj: TAlgosimNumericEntity; const AEps: TASR); virtual; abstract;
    procedure DoExecute; override; final;
  end;

  [&Function('IsPositive')]
  [&Category(fcMath)]
  FCN_IsPositive = class(TNumEntEpsilonFunction)
  protected
    procedure fcn(AObj: TAlgosimNumericEntity; const AEps: TASR); override;
  end;

  [&Function('IsNonNegative')]
  [&Category(fcMath)]
  FCN_IsNonNegative = class(TNumEntEpsilonFunction)
  protected
    procedure fcn(AObj: TAlgosimNumericEntity; const AEps: TASR); override;
  end;

  [&Function('IsNegative')]
  [&Category(fcMath)]
  FCN_IsNegative = class(TNumEntEpsilonFunction)
  protected
    procedure fcn(AObj: TAlgosimNumericEntity; const AEps: TASR); override;
  end;

  [&Function('IsNonPositive')]
  [&Category(fcMath)]
  FCN_IsNonPositive = class(TNumEntEpsilonFunction)
  protected
    procedure fcn(AObj: TAlgosimNumericEntity; const AEps: TASR); override;
  end;

  [&Function('IsZero')]
  [&Category(fcMath)]
  FCN_IsZero = class(TNumEntEpsilonFunction)
  protected
    procedure fcn(AObj: TAlgosimNumericEntity; const AEps: TASR); override;
  end;

  [&Function('IsNonZero')]
  [&Category(fcMath)]
  FCN_IsNonZero = class(TNumEntEpsilonFunction)
  protected
    procedure fcn(AObj: TAlgosimNumericEntity; const AEps: TASR); override;
  end;

  [&Function('PivotPos')]
  [&Category(fcMath)]
  FCN_PivotPos = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsZeroRow')]
  [&Category(fcMath)]
  FCN_IsZeroRow = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsEssentiallyZeroRow')]
  [&Category(fcMath)]
  FCN_IsEssentiallyZeroRow = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsDiagonallyDominant')]
  [&Category(fcMath)]
  FCN_IsDiagonallyDominant = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsStrictlyDiagonallyDominant')]
  [&Category(fcMath)]
  FCN_IsStrictlyDiagonallyDominant = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('commute')]
  [&Category(fcMath)]
  FCN_CommutesWith = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ToLowerTriangular')]
  [&Category(fcMath)]
  FCN_ToLowerTriangular = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ToUpperTriangular')]
  [&Category(fcMath)]
  FCN_ToUpperTriangular = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ToUpperHessenberg')]
  [&Category(fcMath)]
  FCN_ToUpperHessenberg = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('HermitianSquare')]
  [&Category(fcMath)]
  FCN_HermitianSquare = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('modulus')]
  [&Category(fcMath)]
  FCN_Modulus = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('determinant', 'det')]
  [&Category(fcMath)]
  FCN_Determinant = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('tr')]
  [&Category(fcMath)]
  FCN_Trace = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('inv')]
  [&Category(fcMath)]
  FCN_Inverse = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('rank')]
  [&Category(fcMath)]
  FCN_Rank = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('nullity')]
  [&Category(fcMath)]
  FCN_Nullity = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ConditionNumber')]
  [&Category(fcMath)]
  FCN_ConditionNumber = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsSingular')]
  [&Category(fcMath)]
  FCN_IsSingular = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DeletedAbsoluteRowSum')]
  [&Category(fcMath)]
  FCN_DeletedAbsoluteRowSum = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RowSwap')]
  [&Category(fcMath)]
  FCN_RowSwap = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RowScale')]
  [&Category(fcMath)]
  FCN_RowScale = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RowAddMul')]
  [&Category(fcMath)]
  FCN_RowAddMul = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RowEchelonForm')]
  [&Category(fcMath)]
  FCN_RowEchelonForm = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ReducedRowEchelonForm')]
  [&Category(fcMath)]
  FCN_ReducedRowEchelonForm = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ZeroRowCount')]
  [&Category(fcMath)]
  FCN_NumZeroRows = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('TrailingZeroRowCount')]
  [&Category(fcMath)]
  FCN_NumTrailingZeroRows = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('GramSchmidt')]
  [&Category(fcMath)]
  FCN_GramSchmidt = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ColumnSpaceBasis')]
  [&Category(fcMath)]
  FCN_ColumnSpaceBasis = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ColumnSpaceProjection')]
  [&Category(fcMath)]
  FCN_ColumnSpaceProjection = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DistanceFromColumnSpace')]
  [&Category(fcMath)]
  FCN_DistanceFromColumnSpace = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('eigenvalues')]
  [&Category(fcMath)]
  FCN_Eigenvalues = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('spectrum')]
  [&Category(fcMath)]
  FCN_Spectrum = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('eigenvectors')]
  [&Category(fcMath)]
  FCN_Eigenvectors = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsEigenvector')]
  [&Category(fcMath)]
  FCN_IsEigenvector = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('EigenvalueOf')]
  [&Category(fcMath)]
  FCN_EigenvalueOf = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsEigenpair')]
  [&Category(fcMath)]
  FCN_IsEigenpair = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('EigenvectorOf')]
  [&Category(fcMath)]
  FCN_EigenvectorOf = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SpectralRadius')]
  [&Category(fcMath)]
  FCN_SpectralRadius = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SingularValues')]
  [&Category(fcMath)]
  FCN_SingularValues = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('defuzz')]
  [&Category(fcMath)]
  FCN_Defuzz = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('vectorization', 'vec')]
  [&Category(fcMath)]
  FCN_Vectorization = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('aug')]
  [&Category(fcMath)]
  FCN_Aug = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SubmatrixByRemoval')]
  [&Category(fcMath)]
  FCN_SubmatrixByRemoval = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('LeadingPrincipalSubmatrix')]
  [&Category(fcMath)]
  FCN_LeadingPrincipalSubmatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('lessen')]
  [&Category(fcMath)]
  FCN_Lessen = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('minor')]
  [&Category(fcMath)]
  FCN_Minor = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('cofactor')]
  [&Category(fcMath)]
  FCN_Cofactor = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('CofactorMatrix')]
  [&Category(fcMath)]
  FCN_CofactorMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AdjugateMatrix')]
  [&Category(fcMath)]
  FCN_AdjugateMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('LU')]
  [&Category(fcMath)]
  FCN_LU = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Cholesky')]
  [&Category(fcMath)]
  FCN_Cholesky = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('QR')]
  [&Category(fcMath)]
  FCN_QR = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Hessenberg')]
  [&Category(fcMath)]
  FCN_Hessenberg = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SameValue')]
  [&Category(fcGeneral, fcMath)]
  FCN_SameValue = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('CompareValue')]
  [&Category(fcGeneral, fcMath)]
  FCN_CompareValue = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ZeroMatrix')]
  [&Category(fcMath)]
  FCN_ZeroMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ComplexZeroMatrix')]
  [&Category(fcMath)]
  FCN_ComplexZeroMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IdentityMatrix')]
  [&Category(fcMath)]
  FCN_IdentityMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ReversalMatrix')]
  [&Category(fcMath)]
  FCN_ReversalMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RandomMatrix')]
  [&Category(fcMath)]
  FCN_RandomMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RandomIntMatrix')]
  [&Category(fcMath)]
  FCN_RandomIntMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('OuterProduct')]
  [&Category(fcMath)]
  FCN_OuterProduct = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('CirculantMatrix')]
  [&Category(fcMath)]
  FCN_CirculantMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ToeplitzMatrix')]
  [&Category(fcMath)]
  FCN_ToeplitzMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('HankelMatrix')]
  [&Category(fcMath)]
  FCN_HankelMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('BackwardShiftMatrix')]
  [&Category(fcMath)]
  FCN_BackwardShiftMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ForwardShiftMatrix')]
  [&Category(fcMath)]
  FCN_ForwardShiftMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('VandermondeMatrix')]
  [&Category(fcMath)]
  FCN_VandermondeMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('HilbertMatrix')]
  [&Category(fcMath)]
  FCN_HilbertMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RotationMatrix')]
  [&Category(fcMath)]
  FCN_RotationMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ReflectionMatrix')]
  [&Category(fcMath)]
  FCN_ReflectionMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('HadamardProduct')]
  [&Category(fcMath)]
  FCN_HadamardProduct = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DirectSum')]
  [&Category(fcMath)]
  FCN_DirectSum = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ForwardSubstitution')]
  [&Category(fcMath)]
  FCN_ForwardSubstitution = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('BackSubstitution')]
  [&Category(fcMath)]
  FCN_BackSubstitution = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SysSolve')]
  [&Category(fcMath)]
  FCN_SysSolve = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('LeastSquaresPolynomialFit', 'polyfit')]
  [&Category(fcMath)]
  FCN_LeastSquaresPolynomialFit = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AreParallel')]
  [&Category(fcMath)]
  FCN_AreParallel = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AreNotParallel')]
  [&Category(fcMath)]
  FCN_AreNotParallel = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ArePerpendicular')]
  [&Category(fcMath)]
  FCN_ArePerpendicular = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('GetRGB')]
  [&Category(fcPixmaps)]
  FCN_RGBValues = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('GetHSV')]
  [&Category(fcPixmaps)]
  FCN_HSVValues = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('GetHSL')]
  [&Category(fcPixmaps)]
  FCN_HSLValues = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('color')]
  [&Category(fcPixmaps)]
  FCN_Color = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('HexColorCode')]
  [&Category(fcPixmaps)]
  FCN_HexColorCode = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('NamedColors')]
  [&Category(fcPixmaps)]
  FCN_GetNamedColors = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsDark')]
  [&Category(fcPixmaps)]
  FCN_IsDark = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('rgb')]
  [&Category(fcPixmaps)]
  FCN_RGB = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('hsv')]
  [&Category(fcPixmaps)]
  FCN_HSV = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('hsl')]
  [&Category(fcPixmaps)]
  FCN_HSL = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AddMember')]
  [&Category(fcStructures)]
  FCN_AddMember = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RemoveMember')]
  [&Category(fcStructures)]
  FCN_RemoveMember = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SetValue')]
  [&Category(fcStructures)]
  FCN_SetValue = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RenameMember')]
  [&Category(fcStructures)]
  FCN_RenameMember = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('HasMember')]
  [&Category(fcStructures)]
  FCN_HasMember = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('IndexOfName')]
  [&Category(fcStructures)]
  FCN_IndexOfName = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('ToStructType')]
  [&Category(fcStructures)]
  FCN_ToStructType = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('new')]
  [&Category(fcStructures)]
  FCN_New = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('GetStructType')]
  [&Category(fcStructures)]
  FCN_StructType = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RegisterStructType')]
  [&Category(fcStructures)]
  FCN_RegisterStructType = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('UnregisterStructType')]
  [&Category(fcStructures)]
  FCN_UnregisterStructType = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ValidateStruct')]
  [&Category(fcStructures)]
  FCN_ValidateStruct = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('CreatePixmap')]
  [&Category(fcPixmaps)]
  FCN_CreatePixmap = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AddBorder')]
  [&Category(fcPixmaps)]
  FCN_AddBorder = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ExtendBorder')]
  [&Category(fcPixmaps)]
  FCN_ExtendBorder = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ColorFreqs')]
  [&Category(fcPixmaps)]
  FCN_ColorFrequencies = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ColorCount')]
  [&Category(fcPixmaps)]
  FCN_ColorCount = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FillRect')]
  [&Category(fcPixmaps)]
  FCN_FillRect = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DrawRect')]
  [&Category(fcPixmaps)]
  FCN_DrawRect = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AlphaDrawRect')]
  [&Category(fcPixmaps)]
  FCN_AlphaDrawRect = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FixHue')]
  [&Category(fcPixmaps)]
  FCN_FixHue = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ToMonochromatic')]
  [&Category(fcPixmaps)]
  FCN_ToMonochromatic = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ShiftHue')]
  [&Category(fcPixmaps)]
  FCN_ShiftHue = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ToGreyscale')]
  [&Category(fcPixmaps)]
  FCN_ToGreyscale = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('InvertColor')]
  [&Category(fcPixmaps)]
  FCN_InvertColor = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('InvertValue')]
  [&Category(fcPixmaps)]
  FCN_InvertValue = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('InvertLightness')]
  [&Category(fcPixmaps)]
  FCN_InvertLightness = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AdjustRGB')]
  [&Category(fcPixmaps)]
  FCN_RGBAdjustment = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AdjustHSV')]
  [&Category(fcPixmaps)]
  FCN_HSVAdjustment = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('binarize')]
  [&Category(fcPixmaps)]
  FCN_Binarize = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('flip')]
  [&Category(fcPixmaps)]
  FCN_Flip = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('rot90p')]
  [&Category(fcPixmaps)]
  FCN_Rot90P = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('rot90n')]
  [&Category(fcPixmaps)]
  FCN_Rot90N = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('rot180')]
  [&Category(fcPixmaps)]
  FCN_Rot180 = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ScanlineRotation')]
  [&Category(fcPixmaps)]
  FCN_ScanlineRotation = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('CustomScanlineRotation')]
  [&Category(fcPixmaps)]
  FCN_CustomScanlineRotation = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('SkewRotation')]
  [&Category(fcPixmaps)]
  FCN_SkewRotation = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('scale')]
  [&Category(fcPixmaps)]
  FCN_Scale = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('stretch')]
  [&Category(fcPixmaps)]
  FCN_Stretch = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('rotate')]
  [&Category(fcPixmaps)]
  FCN_Rotate = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('shear')]
  [&Category(fcPixmaps)]
  FCN_Shear = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('LinearTransformation')]
  [&Category(fcPixmaps)]
  FCN_ApplyLinearTransformation = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('transformation')]
  [&Category(fcPixmaps)]
  FCN_ApplyTransformation = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('GetRect')]
  [&Category(fcPixmaps)]
  FCN_GetRect = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AverageColor')]
  [&Category(fcPixmaps)]
  FCN_AverageColor = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AutoCropRect')]
  [&Category(fcPixmaps)]
  FCN_GetAutoCropRect = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AutoCrop')]
  [&Category(fcPixmaps)]
  FCN_AutoCrop = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ExpandCanvas')]
  [&Category(fcPixmaps)]
  FCN_ExpandCanvas = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsOnlyBackground')]
  [&Category(fcPixmaps)]
  FCN_OnlyBackground = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('EdgeDetect')]
  [&Category(fcPixmaps)]
  FCN_DetectEdges = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('emboss')]
  [&Category(fcPixmaps)]
  FCN_Emboss = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('pixelate')]
  [&Category(fcPixmaps)]
  FCN_Pixellate = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('noise')]
  [&Category(fcPixmaps)]
  FCN_Noise = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DistortMetric')]
  [&Category(fcPixmaps)]
  FCN_DistortMetric = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DistortColor')]
  [&Category(fcPixmaps)]
  FCN_DistortColor = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('tiles')]
  [&Category(fcPixmaps)]
  FCN_Tiles = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ComponentHighlight')]
  [&Category(fcPixmaps)]
  FCN_ComponentHighlight = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FloodFill')]
  [&Category(fcPixmaps)]
  FCN_FloodFill = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DrawLine')]
  [&Category(fcPixmaps)]
  FCN_DrawLine = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DrawLines')]
  [&Category(fcPixmaps)]
  FCN_DrawLines = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DrawPolygon')]
  [&Category(fcPixmaps)]
  FCN_DrawPolygon = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('convolve')]
  [&Category(fcPixmaps)]
  FCN_Convolve = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ConvolutionKernel')]
  [&Category(fcPixmaps)]
  FCN_ConvolutionKernel = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('MotionBlur')]
  [&Category(fcPixmaps)]
  FCN_MotionBlur = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('BoxBlur')]
  [&Category(fcPixmaps)]
  FCN_BoxBlur = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('GaussianBlur')]
  [&Category(fcPixmaps)]
  FCN_GaussianBlur = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('darken')]
  [&Category(fcPixmaps)]
  FCN_Darken = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('whiten')]
  [&Category(fcPixmaps)]
  FCN_Whiten = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FadeToColor')]
  [&Category(fcPixmaps)]
  FCN_FadeToColor = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DissolveToColorRegularly')]
  [&Category(fcPixmaps)]
  FCN_EveryOtherToColor = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DissolveToColorStochastically')]
  [&Category(fcPixmaps)]
  FCN_RandomToColor = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('wind')]
  [&Category(fcPixmaps)]
  FCN_Wind = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RandomScanlineRotation')]
  [&Category(fcPixmaps)]
  FCN_RandomScanlineRotation = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ripple')]
  [&Category(fcPixmaps)]
  FCN_Ripple = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ExtractChannel')]
  [&Category(fcPixmaps, fcSounds)]
  FCN_ExtractChannel = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('CombineChannels')]
  [&Category(fcPixmaps)]
  FCN_CombineChannels = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsGreyscale')]
  [&Category(fcPixmaps)]
  FCN_IsGreyscale = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DrawDisk')]
  [&Category(fcPixmaps)]
  FCN_DrawDisk = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DrawDisks')]
  [&Category(fcPixmaps)]
  FCN_DrawDisks = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DrawSquare')]
  [&Category(fcPixmaps)]
  FCN_DrawSquare = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DrawSquares')]
  [&Category(fcPixmaps)]
  FCN_DrawSquares = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ColorGradient')]
  [&Category(fcPixmaps)]
  FCN_CreateGradient = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('voronoi')]
  [&Category(fcPixmaps)]
  FCN_Voronoi = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('superpose')]
  [&Category(fcSounds)]
  FCN_SuperposeSounds = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AppendSound')]
  [&Category(fcSounds)]
  FCN_AppendSound = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('echo')]
  [&Category(fcSounds)]
  FCN_EchoSound = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ScaleAmplitude')]
  [&Category(fcSounds)]
  FCN_SoundScaleAmplitude = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ConvertAudio')]
  [&Category(fcSounds)]
  FCN_SoundConvertTo = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SineTone')]
  [&Category(fcSounds)]
  FCN_SineTone = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('WhiteNoise')]
  [&Category(fcSounds)]
  FCN_WhiteNoise = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('MultichannelAudio')]
  [&Category(fcSounds)]
  FCN_MultichannelSound = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FadeSounds')]
  [&Category(fcSounds)]
  FCN_FadeSounds = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ComputeSound')]
  [&Category(fcSounds)]
  FCN_ComputeSound = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('AudioMetadata')]
  [&Category(fcSounds)]
  FCN_SoundMetadata = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('SoundMax')]
  [&Category(fcSounds)]
  FCN_SoundMax = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('PlaySound')]
  [&Category(fcSounds)]
  FCN_PlaySound = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('StopSound')]
  [&Category(fcSounds)]
  FCN_StopSound = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SetInstrument')]
  [&Category(fcMIDI)]
  FCN_SetInstrument = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('GetInstrument')]
  [&Category(fcMIDI)]
  FCN_GetInstrument = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SetVolume')]
  [&Category(fcMIDI)]
  FCN_SetVolume = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('GetVolume')]
  [&Category(fcMIDI)]
  FCN_GetVolume = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('NoteOn')]
  [&Category(fcMIDI)]
  FCN_NoteOn = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('NoteOff')]
  [&Category(fcMIDI)]
  FCN_NoteOff = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('PercussionNoteOn')]
  [&Category(fcMIDI)]
  FCN_PNoteOn = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('PercussionNoteOff')]
  [&Category(fcMIDI)]
  FCN_PNoteOff = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('NoteSilence')]
  [&Category(fcMIDI)]
  FCN_NoteSilence = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('NoteReset')]
  [&Category(fcMIDI)]
  FCN_NoteReset = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('InstrumentInfo')]
  [&Category(fcMIDI)]
  FCN_InstrumentInfo = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('PercussionInstrumentInfo')]
  [&Category(fcMIDI)]
  FCN_PInstrumentInfo = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('NoteName')]
  [&Category(fcMIDI)]
  FCN_NoteName = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('MidiMsg')]
  [&Category(fcMIDI)]
  FCN_MidiMsg = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('label')]
  [&Category(fcLists)]
  FCN_LabelList = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('VarAppend')]
  [&Category(fcGeneral, fcLists)]
  FCN_VarAppend = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('VarExtendWith')]
  [&Category(fcGeneral, fcLists)]
  FCN_VarExtendWith = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('catenate', 'concatenate', 'concat')]
  [&Category(fcGeneral, fcLists)]
  FCN_Catenate = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('VarInsert')]
  [&Category(fcGeneral, fcLists)]
  FCN_VarInsert = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('VarRemove')]
  [&Category(fcGeneral, fcLists)]
  FCN_VarRemove = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('VarTruncate')]
  [&Category(fcGeneral, fcLists)]
  FCN_VarTruncate = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('VarSwap')]
  [&Category(fcGeneral, fcLists)]
  FCN_VarSwap = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('numbers')]
  [&Category(fcGeneral, fcLists)]
  FCN_Numbers = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('CreateFunction')]
  [&Category(fcSystem)]
  FCN_CreateFunction = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('image')]
  [&Category(fcSystem)]
  FCN_Image = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IteratedImage')]
  [&Category(fcSystem)]
  FCN_IteratedImage = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IteratedImages')]
  [&Category(fcSystem)]
  FCN_IteratedImages = class(TASSimpleFunction)
  protected
    var
      FContainerClass: TAlgosimObjectClass;
    procedure SimpleFunction; override;
    procedure InitNode; override;
  end;

  [&Function('orbit')]
  [&Category(fcSystem)]
  FCN_Orbit = class(FCN_IteratedImages)
  protected
    procedure InitNode; override;
  end;

  [&Function('IsNumber')]
  [&Category(fcSystem)]
  FCN_IsNumber = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsVector')]
  [&Category(fcSystem)]
  FCN_IsVector = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsMatrix')]
  [&Category(fcSystem)]
  FCN_IsMatrix = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsText')]
  [&Category(fcSystem)]
  FCN_IsText = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsBoolean')]
  [&Category(fcSystem)]
  FCN_IsBoolean = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsPixmap')]
  [&Category(fcSystem)]
  FCN_IsPixmap = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsSound')]
  [&Category(fcSystem)]
  FCN_IsSound = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsTable')]
  [&Category(fcSystem)]
  FCN_IsTable = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsColor')]
  [&Category(fcSystem)]
  FCN_IsColor = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsSet')]
  [&Category(fcSystem)]
  FCN_IsSet = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsList')]
  [&Category(fcSystem)]
  FCN_IsList = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsStructure')]
  [&Category(fcSystem)]
  FCN_IsStructure = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsReal')]
  [&Category(fcSystem)]
  FCN_IsReal = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsComplex')]
  [&Category(fcSystem)]
  FCN_IsComplex = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsInteger')]
  [&Category(fcSystem)]
  FCN_IsInteger = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsNumericEntity')]
  [&Category(fcSystem)]
  FCN_IsNumericEntity = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsNumericArray')]
  [&Category(fcSystem)]
  FCN_IsNumericArray = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsBinaryData')]
  [&Category(fcSystem)]
  FCN_IsBinaryData = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('entrywise')]
  [&Category(fcLists, fcMath)]
  FCN_entrywise = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('accumulate')]
  [&Category(fcGeneral, fcLists, fcMath)]
  FCN_Accumulate = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AccumulateList')]
  [&Category(fcGeneral, fcLists, fcMath)]
  FCN_AccumulateList = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AccumulateSteps')]
  [&Category(fcGeneral, fcLists, fcMath)]
  FCN_AccumulateSteps = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('rest')]
  [&Category(fcGeneral, fcLists)]
  FCN_Rest = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('append')]
  [&Category(fcGeneral, fcLists)]
  FCN_Append = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ExtendWith')]
  [&Category(fcGeneral, fcLists)]
  FCN_ExtendWith = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('insert')]
  [&Category(fcGeneral, fcLists)]
  FCN_Insert = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('remove')]
  [&Category(fcGeneral, fcLists)]
  FCN_Remove = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('truncate')]
  [&Category(fcGeneral, fcLists)]
  FCN_Truncate = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('swap')]
  [&Category(fcGeneral, fcLists)]
  FCN_Swap = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SortBy')]
  [&Category(fcGeneral, fcLists)]
  FCN_SortBy = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('member')]
  [&Category(fcStructures)]
  FCN_Member = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('GroupBy')]
  [&Category(fcGeneral, fcLists)]
  FCN_GroupBy = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('characters')]
  [&Category(fcStrings)]
  FCN_Characters = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('words')]
  [&Category(fcStrings)]
  FCN_Words = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('do')]
  [&Category(fcSystem)]
  FCN_Do = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('divides')]
  [&Category(fcMath)]
  FCN_Divides = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('NotDivides')]
  [&Category(fcMath)]
  FCN_NotDivides = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('primorial')]
  [&Category(fcMath)]
  FCN_Primorial = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('inc')]
  [&Category(fcMath)]
  FCN_Inc = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('dec')]
  [&Category(fcMath)]
  FCN_Dec = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('variables')]
  [&Category(fcSystem)]
  FCN_Variables = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('LastError')]
  [&Category(fcSystem)]
  FCN_LastError = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('functions')]
  [&Category(fcSystem)]
  FCN_Functions = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  TKernelFunctionFcn = class abstract(TASSimpleFunction)
  protected
    procedure SimpleFunction; override; final;
    procedure Fcn(AFcnClass: TASFunctionClass); virtual; abstract;
  end;

  [&Function('function')]
  [&Category(fcSystem)]
  FCN_Function = class(TKernelFunctionFcn)
  protected
    procedure Fcn(AFcnClass: TASFunctionClass); override;
  end;

  [&Function('categories')]
  [&Category(fcSystem)]
  FCN_Categories = class(TKernelFunctionFcn)
  protected
    procedure Fcn(AFcnClass: TASFunctionClass); override;
  end;

  [&Function('FcnName')]
  [&Category(fcSystem)]
  FCN_FcnName = class(TKernelFunctionFcn)
  protected
    procedure Fcn(AFcnClass: TASFunctionClass); override;
  end;

  [&Function('FcnNames')]
  [&Category(fcSystem)]
  FCN_FcnNames = class(TKernelFunctionFcn)
  protected
    procedure Fcn(AFcnClass: TASFunctionClass); override;
  end;

  [&Function('ErrorInfo')]
  [&Category(fcSystem)]
  FCN_ErrorInfo = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('succ')]
  [&Category(fcMath)]
  FCN_Succ = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('pred')]
  [&Category(fcMath)]
  FCN_Pred = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('LoadDefVars')]
  [&Category(fcSystem)]
  FCN_LoadDefVars = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('operators')]
  [&Category(fcSystem)]
  FCN_Operators = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('if')]
  [&Category(fcSystem)]
  FCN_If = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('ForEach')]
  [&Category(fcGeneral, fcLists, fcStrings, fcStructures, fcSets)]
  FCN_ForEach = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('print')]
  [&Category(fcSystem)]
  FCN_Print = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RemoveBuffer')]
  [&Category(fcSystem)]
  FCN_RemoveBuffer = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('BufferText')]
  [&Category(fcSystem)]
  FCN_BufferText = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('buffers')]
  [&Category(fcSystem)]
  FCN_Buffers = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('MessageBox')]
  [&Category(fcSystem)]
  FCN_MessageBox = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('InputBox')]
  [&Category(fcSystem)]
  FCN_InputBox = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FormatDateTime')]
  [&Category(fcDateTime)]
  FCN_FormatDateTime = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DateTimeString')]
  [&Category(fcDateTime)]
  FCN_DateTimeString = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DateString')]
  [&Category(fcDateTime)]
  FCN_DateString = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('TimeString')]
  [&Category(fcDateTime)]
  FCN_TimeString = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('while')]
  [&Category(fcSystem)]
  FCN_While = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('until')]
  [&Category(fcSystem)]
  FCN_Until = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('repeat')]
  [&Category(fcSystem)]
  FCN_Repeat = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('for')]
  [&Category(fcSystem)]
  FCN_For = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('tokenize')]
  [&Category(fcSystem)]
  FCN_Tokenize = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('parse')]
  [&Category(fcSystem)]
  FCN_Parse = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('WordWrap')]
  [&Category(fcStrings)]
  FCN_WordWrap = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('history')]
  [&Category(fcSystem)]
  FCN_History = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('input')]
  [&Category(fcSystem)]
  FCN_Input = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('inputs')]
  [&Category(fcSystem)]
  FCN_Inputs = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('output')]
  [&Category(fcSystem)]
  FCN_Output = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('HistoryLength')]
  [&Category(fcSystem)]
  FCN_HistoryLength = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ClearHistory')]
  [&Category(fcSystem)]
  FCN_ClearHistory = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SaveHistory')]
  [&Category(fcSystem)]
  FCN_SaveHistory = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SelfTest')]
  [&Category(fcSystem)]
  FCN_SelfTest = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('bases')]
  [&Category(fcSystem)]
  FCN_Bases = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FcnExpr')]
  [&Category(fcSystem)]
  FCN_FcnExpr = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RandomColor')]
  [&Category(fcPixmaps)]
  FCN_RandomColor = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('compute')]
  [&Category(fcLists, fcMath, fcGeneral)]
  FCN_Compute = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('DebugObject')]
  [&Category(fcSystem)]
  FCN_DebugObject = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('CompareString')]
  [&Category(fcStrings)]
  FCN_CompareString = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsCharacter')]
  [&Category(fcSystem)]
  FCN_IsCharacter = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsRealType')]
  [&Category(fcSystem)]
  FCN_IsRealType = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsComplexType')]
  [&Category(fcSystem)]
  FCN_IsComplexType = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('break')]
  [&Category(fcSystem)]
  FCN_Break = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('continue')]
  [&Category(fcSystem)]
  FCN_Continue = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SquareWave')]
  [&Category(fcMath)]
  FCN_SquareWave = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('TriangleWave')]
  [&Category(fcMath)]
  FCN_TriangleWave = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('SawtoothWave')]
  [&Category(fcMath)]
  FCN_SawtoothWave = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('BlendModes')]
  [&Category(fcPixmaps)]
  FCN_BlendModes = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  TNamedObjFcn = class abstract(TASFunction)
  protected
    procedure DoExecute; override; final;
    procedure HandleNamedObject(AObject: TAlgosimObject; const AName: string);
      virtual; abstract;
  end;

  [&Function('display')]
  [&Category(fcSystem)]
  FCN_Display = class(TNamedObjFcn)
  protected
    procedure HandleNamedObject(AObject: TAlgosimObject; const AName: string);
      override;
  end;

  [&Function('window')]
  [&Category(fcSystem)]
  FCN_Window = class(TNamedObjFcn)
  protected
    procedure HandleNamedObject(AObject: TAlgosimObject; const AName: string);
      override;
  end;

  [&Function('ComputePixmap')]
  [&Category(fcPixmaps)]
  FCN_ComputePixmap = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('ColorDialog')]
  [&Category(fcSystem)]
  FCN_ColorDialog = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FontDialog')]
  [&Category(fcSystem)]
  FCN_FontDialog = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FileExists')]
  [&Category(fcSystem)]
  FCN_FileExists = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FileSize')]
  [&Category(fcSystem)]
  FCN_FileSize = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FileName')]
  [&Category(fcSystem)]
  FCN_FileName = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('PrettyFileName')]
  [&Category(fcSystem)]
  FCN_PrettyFileName = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FilePath')]
  [&Category(fcSystem)]
  FCN_FilePath = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FileExt')]
  [&Category(fcSystem)]
  FCN_FileExt = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DeleteFile')]
  [&Category(fcSystem)]
  FCN_DeleteFile = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('CreateDirectory')]
  [&Category(fcSystem)]
  FCN_CreateDirectory = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DeleteDirectory')]
  [&Category(fcSystem)]
  FCN_DeleteDirectory = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DirectoryExists')]
  [&Category(fcSystem)]
  FCN_DirectoryExists = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FileList')]
  [&Category(fcSystem)]
  FCN_FileList = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DirectoryList')]
  [&Category(fcSystem)]
  FCN_DirectoryList = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FileOpenDialog')]
  [&Category(fcSystem)]
  FCN_FileOpenDialog = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FileSaveDialog')]
  [&Category(fcSystem)]
  FCN_FileSaveDialog = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('IsCarolNumber')]
  [&Category(fcMath, fcNumberTheory)]
  FCN_IsCarolNumber = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('StructKeys')]
  [&Category(fcSystem)]
  FCN_StructKeys = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('digits')]
  [&Category(fcSystem)]
  FCN_Digits = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('FractionParts')]
  [&Category(fcSystem)]
  FCN_FractionParts = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ExampleData')]
  [&Category(fcGeneral)]
  FCN_ExampleData = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('LeftAlign')]
  [&Category(fcTables)]
  FCN_LeftAlign = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RightAlign')]
  [&Category(fcTables)]
  FCN_RightAlign = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('CenterText')]
  [&Category(fcTables)]
  FCN_CenterText = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('MatrixPlot')]
  [&Category(fcMath, fcPixmaps)]
  FCN_MatrixPlot = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('diagram')]
  [&Category(fcVisualization)]
  FCN_Diagram = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('scene')]
  [&Category(fcVisualization)]
  FCN_Scene = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  TASVisualizationFunction = class(TASSimpleFunction)
  strict protected
    FVisual: TObject;
    procedure SimpleFunction; override;
  public
    destructor Destroy; override;
  end;

  [&Function('BarChart')]
  [&Category(fcVisualization)]
  FCN_BarChart = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('PieChart')]
  [&Category(fcVisualization)]
  FCN_PieChart = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('histogram')]
  [&Category(fcVisualization)]
  FCN_Histogram = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ScatterPlot')]
  [&Category(fcVisualization)]
  FCN_ScatterPlot = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('LineChart', 'LinePlot')]
  [&Category(fcVisualization)]
  FCN_LineChart = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AreaChart')]
  [&Category(fcVisualization)]
  FCN_AreaChart = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('graph')]
  [&Category(fcSystem, fcVisualization)]
  FCN_Graph = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('plot')]
  [&Category(fcVisualization)]
  FCN_Plot = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('heatmap')]
  [&Category(fcVisualization)]
  FCN_Heatmap = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('VectorField')]
  [&Category(fcVisualization)]
  FCN_VectorField = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('RemoveVisual')]
  [&Category(fcVisualization)]
  FCN_RemoveVisual = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('AdjustVisual')]
  [&Category(fcVisualization)]
  FCN_AdjustVisual = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('LineSegment')]
  [&Category(fcVisualization)]
  FCN_LineSegment = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('rectangle')]
  [&Category(fcVisualization)]
  FCN_Rectangle = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('circle')]
  [&Category(fcVisualization)]
  FCN_Circle = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('disk')]
  [&Category(fcVisualization)]
  FCN_Disk = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('polygon')]
  [&Category(fcVisualization)]
  FCN_Polygon = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('text')]
  [&Category(fcVisualization)]
  FCN_Text = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('EmbedPixmap')]
  [&Category(fcPixmaps, fcVisualization)]
  FCN_EmbedPixmap = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('speak')]
  [&Category(fcSystem)]
  FCN_Speak = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('surface', 'surf')]
  [&Category(fcVisualization)]
  FCN_Surface = class(TASFunction)
  protected
    procedure DoExecute; override;
  end;

  [&Function('curve')]
  [&Category(fcVisualization)]
  FCN_Curve = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('sphere')]
  [&Category(fcVisualization)]
  FCN_Sphere = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ellipsoid')]
  [&Category(fcVisualization)]
  FCN_Ellipsoid = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('cylinder')]
  [&Category(fcVisualization)]
  FCN_Cylinder = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('cone')]
  [&Category(fcVisualization)]
  FCN_Cone = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('plane')]
  [&Category(fcVisualization)]
  FCN_Plane = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('InfinitePlane')]
  [&Category(fcVisualization)]
  FCN_InfinatePlane = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('disk3D')]
  [&Category(fcVisualization)]
  FCN_Disk3D = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('solid')]
  [&Category(fcVisualization)]
  FCN_Solid = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('model')]
  [&Category(fcVisualization)]
  FCN_Model = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('CoordinateAxes')]
  [&Category(fcVisualization)]
  FCN_CoordinateAxes = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('clamp')]
  [&Category(fcMath)]
  FCN_Clamp = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('paste')]
  [&Category(fcSystem)]
  FCN_Paste = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ClearScene')]
  [&Category(fcVisualization)]
  FCN_ClearScene = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ClearDiagram')]
  [&Category(fcVisualization)]
  FCN_ClearDiagram = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('VisualObject')]
  [&Category(fcVisualization)]
  FCN_VisualObject = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('VisualObjects')]
  [&Category(fcVisualization)]
  FCN_VisualObjects = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('MemoryUsage')]
  [&Category(fcSystem)]
  FCN_MemoryUsage = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('arrow')]
  [&Category(fcVisualization)]
  FCN_Arrow = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('Roman')]
  [&Category(fcSystem)]
  FCN_Roman = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ParseDate')]
  [&Category(fcDateTime)]
  FCN_ParseDate = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ParseTime')]
  [&Category(fcDateTime)]
  FCN_ParseTime = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ParseDateTime')]
  [&Category(fcDateTime)]
  FCN_ParseDateTime = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('deltas')]
  [&Category(fcGeneral, fcLists, fcMath)]
  FCN_Deltas = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('MovingAverage')]
  [&Category(fcMath)]
  FCN_MovingAverage = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('settings')]
  [&Category(fcSystem)]
  FCN_Settings = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('setting')]
  [&Category(fcSystem)]
  FCN_Setting = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ApplySetting')]
  [&Category(fcSystem)]
  FCN_ApplySetting = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ContourPlot')]
  [&Category(fcVisualization)]
  FCN_ContourPlot = class(TASVisualizationFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('panels')]
  [&Category(fcSystem)]
  FCN_Panels = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ClosePanel')]
  [&Category(fcSystem)]
  FCN_ClosePanel = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('DebugLog')]
  [&Category(fcSystem)]
  FCN_DebugLog = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;

  [&Function('ApplyLayout')]
  [&Category(fcSystem)]
  FCN_ApplyLayout = class(TASSimpleFunction)
  protected
    procedure SimpleFunction; override;
  end;


var
  FixedTime: TDateTime;

implementation

uses
  Windows, Math, StrUtils, DateUtils, ASPropMan, ASPropStores, ASStrFcns,
  UnicodeData, ASTable, ASColors, ASPixmap, ASSounds, ASMIDI, ASTokenizer,
  ASParser, SyncObjs, IOUtils, ASNumUtils, ASVisualization, VisCtl2D, rgl,
  ASSpeech, Clipbrd, ClientVisuals, PsAPI, RomanNumerals, ASSettings,
  ASContours, UxPanel;

const
  DefPlotN = 2000;

function GetCurDate: TDateTime;
begin
  if FixedTime <> 0.0 then
    Result := DateOf(FixedTime)
  else
    Result := SysUtils.Date
end;

function GetCurTime: TDateTime;
begin
  if FixedTime <> 0.0 then
    Result := TimeOf(FixedTime)
  else
    Result := SysUtils.Time
end;

function GetCurDateTime: TDateTime;
begin
  if FixedTime <> 0.0 then
    Result := FixedTime
  else
    Result := SysUtils.Now
end;

function GetYesterday: TDateTime;
begin
  if FixedTime <> 0.0 then
    Result := GetCurDate - 1 // mimics the implementation of DateUtils.Yesterday
  else
    Result := DateUtils.Yesterday
end;

function GetTomorrow: TDateTime;
begin
  if FixedTime <> 0.0 then
    Result := GetCurDate + 1 // mimics the implementation of DateUtils.Tomorrow
  else
    Result := DateUtils.Tomorrow;
end;


{ FCN_Identity }

procedure FCN_Identity.SimpleFunction;
begin
  Args.MoveObject(Value).Close;
end;

{ FCN_Add }

procedure FCN_Add.SimpleFunction;
var
  Args: TArgumentExtractor;
  Right: TAlgosimObject;
begin

  Args := Self.Args;

  if Args.Count = 0 then
  begin
    Result := ASO(0);
    Exit;
  end;

  Args := Args.MoveObject(Value);

  while Args.ArgExists do
  begin

    Args := Args.Extract(Right);

    if (Value is TAlgosimNumber) and (Right is TAlgosimNumber) then
      TObjReplacer<TAlgosimObject>.Replace(Value, TAlgosimNumber.Add(TAlgosimNumber(Value), TAlgosimNumber(Right)))

    else if (Value is TAlgosimVector) and (Right is TAlgosimVector) then
      TObjReplacer<TAlgosimObject>.Replace(Value, TAlgosimVector.Add(TAlgosimVector(Value), TAlgosimVector(Right)))

    else if (Value is TAlgosimMatrix) and (Right is TAlgosimMatrix) then
      TObjReplacer<TAlgosimObject>.Replace(Value, TAlgosimMatrix.Add(TAlgosimMatrix(Value), TAlgosimMatrix(Right)))

    else if (Value is TAlgosimString) and (Right is TAlgosimString) then
      TObjReplacer<TAlgosimObject>.Replace(Value, ASO(TAlgosimString(Value).Value + TAlgosimString(Right).Value))

    else if Value is TAlgosimString then
      TObjReplacer<TAlgosimObject>.Replace(Value, ASO(TAlgosimString(Value).Value + Right.GetAsSingleLineText(Context.FormatOptions)))

    else if (Value is TAlgosimVector) and (Right is TAlgosimNumber) then
      TObjReplacer<TAlgosimObject>.Replace(Value, TAlgosimVector.Add(TAlgosimVector(Value), TAlgosimNumber(Right)))

    else if (Value is TAlgosimMatrix) and (Right is TAlgosimNumber) then
      TObjReplacer<TAlgosimObject>.Replace(Value, TAlgosimMatrix.Add(TAlgosimMatrix(Value), TAlgosimNumber(Right)))

    else if (Value is TAlgosimSound) and (Right is TAlgosimSound) then
      TObjReplacer<TAlgosimObject>.Replace(Value, ASO(TAlgosimSound(Value).Value + TAlgosimSound(Right).Value))

    else
      ErrInvalidArguments;

  end;

end;

{ FCN_Subtract }

procedure FCN_Subtract.SimpleFunction;
var
  Left, Right: TAlgosimObject;
begin

  Args.Extract(Left).Extract(Right).Close;

  if (Left is TAlgosimNumber) and (Right is TAlgosimNumber) then
    Result := TAlgosimNumber.Subtract(TAlgosimNumber(Left), TAlgosimNumber(Right))

  else if (Left is TAlgosimVector) and (Right is TAlgosimVector) then
    Result := TAlgosimVector.Subtract(TAlgosimVector(Left), TAlgosimVector(Right))

  else if (Left is TAlgosimMatrix) and (Right is TAlgosimMatrix) then
    Result := TAlgosimMatrix.Subtract(TAlgosimMatrix(Left), TAlgosimMatrix(Right))

  else if (Left is TAlgosimVector) and (Right is TAlgosimNumber) then
    Result := TAlgosimVector.Subtract(TAlgosimVector(Left), TAlgosimNumber(Right))

  else if (Left is TAlgosimMatrix) and (Right is TAlgosimNumber) then
    Result := TAlgosimMatrix.Subtract(TAlgosimMatrix(Left), TAlgosimNumber(Right))

  else if (Left is TAlgosimSound) and (Right is TAlgosimSound) then
    Result := ASO(TAlgosimSound(Left).Value - TAlgosimSound(Right).Value)

  else
    ErrInvalidArguments;

end;

{ FCN_UnaryMinus }

procedure FCN_UnaryMinus.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := Obj.UnaryMinus;
end;

{ FCN_Multiply }

procedure FCN_Multiply.SimpleFunction;
var
  Args: TArgumentExtractor;
  Right: TAlgosimObject;
  IntVal: Integer;
  RealVal: TASR;
begin

  Args := Self.Args;

  if Args.Count = 0 then
  begin
    Result := ASO(1);
    Exit;
  end;

  Args := Args.MoveObject(Value);

  while Args.ArgExists do
  begin

    Args := Args.Extract(Right);

    if (Value is TAlgosimNumber) and (Right is TAlgosimNumber) then
      TObjReplacer<TAlgosimObject>.Replace(Value, TAlgosimNumber.Multiply(TAlgosimNumber(Value), TAlgosimNumber(Right)))

    else if (Value is TAlgosimVector) and (Right is TAlgosimVector) then
      TObjReplacer<TAlgosimObject>.Replace(Value, TAlgosimVector.InnerProduct(TAlgosimVector(Value), TAlgosimVector(Right)))

    else if (Value is TAlgosimMatrix) and (Right is TAlgosimMatrix) then
      TObjReplacer<TAlgosimObject>.Replace(Value, TAlgosimMatrix.Multiply(TAlgosimMatrix(Value), TAlgosimMatrix(Right)))

    else if (Value is TAlgosimNumber) and (Right is TAlgosimVector) then
      TObjReplacer<TAlgosimObject>.Replace(Value, TAlgosimVector.Multiply(TAlgosimVector(Right), TAlgosimNumber(Value)))

    else if (Value is TAlgosimVector) and (Right is TAlgosimNumber) then
      TObjReplacer<TAlgosimObject>.Replace(Value, TAlgosimVector.Multiply(TAlgosimVector(Value), TAlgosimNumber(Right)))

    else if (Value is TAlgosimNumber) and (Right is TAlgosimMatrix) then
      TObjReplacer<TAlgosimObject>.Replace(Value, TAlgosimMatrix.Multiply(TAlgosimMatrix(Right), TAlgosimNumber(Value)))

    else if (Value is TAlgosimMatrix) and (Right is TAlgosimNumber) then
      TObjReplacer<TAlgosimObject>.Replace(Value, TAlgosimMatrix.Multiply(TAlgosimMatrix(Value), TAlgosimNumber(Right)))

    else if (Value is TAlgosimMatrix) and (Right is TAlgosimVector) then
      TObjReplacer<TAlgosimObject>.Replace(Value, TAlgosimMatrix.Multiply(TAlgosimMatrix(Value), TAlgosimVector(Right)))

    else if (Right is TAlgosimString) and (Value is TAlgosimNumber) and Value.TryToInt32(IntVal) and (IntVal >= 0) then
      TObjReplacer<TAlgosimObject>.Replace(Value, ASO(DupeString(TAlgosimString(Right).Value, IntVal)))

    else if (Value is TAlgosimString) and (Right is TAlgosimNumber) and Right.TryToInt32(IntVal) and (IntVal >= 0) then
      TObjReplacer<TAlgosimObject>.Replace(Value, ASO(DupeString(TAlgosimString(Value).Value, IntVal)))

    else if (Right is TAlgosimSound) and (Value is TAlgosimNumber) and Value.TryToASR(RealVal) then
      TObjReplacer<TAlgosimObject>.Replace(Value, ASO(RealVal * TAlgosimSound(Right).Value))

    else if (Value is TAlgosimSound) and (Right is TAlgosimSound) then
      TObjReplacer<TAlgosimObject>.Replace(Value, ASO(TAlgosimSound(Value).Value * TAlgosimSound(Right).Value))

    else
      ErrInvalidArguments;

  end;

end;

{ FCN_InnerProduct }

procedure FCN_InnerProduct.SimpleFunction;
var
  L, R: TAlgosimVector;
begin
  Args.Extract(L).Extract(R).Close;
  Result := TAlgosimVector.InnerProduct(L, R);
end;

{ FCN_Divide }

procedure FCN_Divide.SimpleFunction;
var
  Left, Right: TAlgosimObject;
begin

  Args.Extract(Left).Extract(Right).Close;

  if (Left is TAlgosimNumber) and (Right is TAlgosimNumber) then
    Result := TAlgosimNumber.Divide(TAlgosimNumber(Left), TAlgosimNumber(Right))

  else if (Left is TAlgosimVector) and (Right is TAlgosimNumber) then
    Result := TAlgosimVector.Divide(TAlgosimVector(Left), TAlgosimNumber(Right))

  else if (Left is TAlgosimMatrix) and (Right is TAlgosimNumber) then
    Result := TAlgosimMatrix.Divide(TAlgosimMatrix(Left), TAlgosimNumber(Right))

  else
    ErrInvalidArguments;

end;

{ FCN_Power }

procedure FCN_Power.SimpleFunction;
var
  Left, Right: TAlgosimObject;
  IntVal: Integer;
begin

  Args.Extract(Left).Extract(Right).Close;

  if (Left is TAlgosimNumber) and (Right is TAlgosimNumber) then
    Result := TAlgosimNumber.Power(TAlgosimNumber(Left), TAlgosimNumber(Right))

  else if (Left is TAlgosimMatrix) and (Right is TAlgosimNumber) and Right.TryToInt32(IntVal) then
    Result := TAlgosimMatrix(Left).Power(IntVal)

  else if (Left is TAlgosimSet) and (Right is TAlgosimNumber) and Right.TryToInt32(IntVal) and (IntVal > 0) then
    Result := TAlgosimSet.CartesianProduct(TAlgosimSet(Left), IntVal)

  else if (Left is TAlgosimArray) and (Right is TAlgosimNumber) and Right.TryToInt32(IntVal) and (IntVal > 0) then
    Result := TAlgosimArray.CartesianProduct(TAlgosimArray(Left), IntVal)

  else
    ErrInvalidArguments;

end;

{ FCN_Cross }

procedure FCN_Cross.SimpleFunction;
var
  Args: TArgumentExtractor;
  Right: TAlgosimVector;
  U, V: TAlgosimSet;
  sets: array of TAlgosimSet;
  arrs: array of TAlgosimArray;
begin
  Args := Self.Args;
  if Args.PeekAt(0) is TAlgosimVector then
  begin
    Args := Args.MoveObject(Value);
    while Args.ArgExists do
    begin
      Args := Args.Extract(Right);
      TObjReplacer<TAlgosimObject>.Replace(Value, TAlgosimVector.CrossProduct(TAlgosimVector(Value), Right))
    end;
  end
  else if Args.PeekAt(0) is TAlgosimArray then
  begin
    SetLength(arrs, Args.Count);
    for var i := 0 to Args.Count - 1 do
      Args := Args.Extract(arrs[i]);
    Result := TAlgosimArray.CartesianProduct(arrs);
  end
  else
  begin
    if Args.Count = 2 then // because it might be slightly faster
    begin
      Args.Extract(U).Extract(V).Close;
      Result := TAlgosimSet.CartesianProduct(U, V);
    end
    else
    begin
      SetLength(sets, Args.Count);
      for var i := 0 to Args.Count - 1 do
        Args := Args.Extract(sets[i]);
      Result := TAlgosimSet.CartesianProduct(sets);
    end;
  end;
end;

{ FCN_CrossProduct }

procedure FCN_CrossProduct.SimpleFunction;
var
  Right: TAlgosimVector;
  Args: TArgumentExtractor;
begin
  Args := Self.Args.MoveObject<TAlgosimVector>(Value);
  while Args.ArgExists do
  begin
    Args := Args.Extract(Right);
    TObjReplacer<TAlgosimObject>.Replace(Value, TAlgosimVector.CrossProduct(TAlgosimVector(Value), Right))
  end;
end;


{ FCN_Angle }

procedure FCN_Angle.SimpleFunction;
var
  Left, Right: TAlgosimVector;
begin
  Args.Extract(Left).Extract(Right).Close;
  Result := TAlgosimVector.Angle(Left, Right);
end;

{ FCN_Factorial }

procedure FCN_Factorial.SimpleFunction;
var
  N: Integer;
begin
  Args.ExtractNonNeg(N).Close;
  if InRange(N, Low(intfactorials), High(intfactorials)) then
    Result := ASOInt(intfactorials[N])
  else
    Result := ASO(factorial(N));
end;

{ FCN_Modulus }

procedure FCN_Absolute.SimpleFunction;
var
  Arg: TAlgosimNumericEntity;
begin
  Args.Extract(Arg).Close;
  Result := Arg.Abs;
end;

{ FCN_ConjugateTranspose }

procedure FCN_ConjugateTranspose.SimpleFunction;
var
  Arg: TAlgosimNumericEntity;
begin
  Args.Extract(Arg).Close;
  if Arg is TAlgosimNumber then
    Result := TAlgosimNumber(Arg).Conjugate
  else
    Result := Arg.ConjugateTranspose;
end;

{ FCN_Transpose }

procedure FCN_Transpose.SimpleFunction;
var
  Arg: TAlgosimObject;
begin

  Args.Extract(Arg).Close;

  if Arg is TAlgosimNumericEntity then
    Result := TAlgosimNumericEntity(Arg).Transpose

  else if Arg is TAlgosimArray then
    Result := TAlgosimArray(Arg).Transpose

  else
    ErrInvalidArguments;

end;

{ FCN_Argument }

procedure FCN_Argument.SimpleFunction;
var
  Arg: TAlgosimNumber;
begin
  Args.Extract(Arg).Close;
  Result := Arg.Argument;
end;

{ FCN_RealPart }

procedure FCN_RealPart.SimpleFunction;
var
  Arg: TAlgosimNumericEntity;
begin
  Args.Extract(Arg).Close;
  Result := Arg.RealPart;
end;

{ FCN_ImaginaryPart }

procedure FCN_ImaginaryPart.SimpleFunction;
var
  Arg: TAlgosimNumericEntity;
begin
  Args.Extract(Arg).Close;
  Result := Arg.ImaginaryPart;
end;

{ FCN_sqrt }

procedure FCN_Sqrt.SimpleFunction;
const
  rdom_sqrt: TSDD = (a: 0; Kind: sddGeq; Complement: False);
var
  Arg: TAlgosimNumericEntity;
begin

  Args.Extract(Arg).Close;

  if Arg is TAlgosimNumber then
    Result := TAlgosimNumber(Arg).ComputeFunction(rdom_sqrt, sqrt, csqrt)

  else if Arg is TAlgosimMatrix then
  begin
    if Arg is TAlgosimRealMatrix then
      Result := ASO(sqrt(TAlgosimRealMatrix(Arg).Value))
    else if Arg is TAlgosimComplexMatrix then
      Result := ASO(sqrt(TAlgosimComplexMatrix(Arg).Value));
  end

  else
    ErrInvalidArguments;

end;

{ FCN_Deg }

class constructor FCN_Deg.ClassCreate;
begin
  PiDiv180 := ASO(Pi / 180);
end;

class destructor FCN_Deg.ClassDestroy;
begin
  FreeAndNil(PiDiv180);
end;

procedure FCN_Deg.SimpleFunction;
var
  Arg: TAlgosimNumber;
begin
  Args.Extract(Arg).Close;
  Result := TAlgosimNumber.Multiply(Arg, PiDiv180);
end;

{ FCN_Percent }

class constructor FCN_Percent.ClassCreate;
begin
  OneHundredth := ASO(1 / 100);
end;

class destructor FCN_Percent.ClassDestroy;
begin
  FreeAndNil(OneHundredth);
end;

procedure FCN_Percent.SimpleFunction;
var
  Arg: TAlgosimNumber;
begin
  Args.Extract(Arg).Close;
  Result := TAlgosimNumber.Multiply(Arg, OneHundredth);
end;

{ FCN_Permille }

class constructor FCN_Permille.ClassCreate;
begin
  OneThousandth := ASO(1 / 1000);
end;

class destructor FCN_Permille.ClassDestroy;
begin
  FreeAndNil(OneThousandth);
end;

procedure FCN_Permille.SimpleFunction;
var
  Arg: TAlgosimNumber;
begin
  Args.Extract(Arg).Close;
  Result := TAlgosimNumber.Multiply(Arg, OneThousandth);
end;

{ FCN_Square }

procedure FCN_Square.SimpleFunction;
var
  Arg: TAlgosimNumericEntity;
begin
  Args.Extract(Arg).Close;
  Result := Arg.Square;
end;

{ FCN_sin }

procedure FCN_sin.InitNode;
begin
  rfcn := sin;
  cfcn := csin;
end;

{ FCN_cos }

procedure FCN_cos.InitNode;
begin
  rfcn := cos;
  cfcn := ccos;
end;

{ FCN_tan }

procedure FCN_tan.InitNode;
begin
  rfcn := tan;
  cfcn := ctan;
end;

{ FCN_cot }

procedure FCN_cot.InitNode;
begin
  rfcn := cot;
  cfcn := ccot;
end;

{ FCN_sec }

procedure FCN_sec.InitNode;
begin
  rfcn := sec;
  cfcn := csec;
end;

{ FCN_csc }

procedure FCN_csc.InitNode;
begin
  rfcn := csc;
  cfcn := ccsc;
end;

{ FCN_arcsin }

procedure FCN_arcsin.InitNode;
const
  rdom_arcsin: TSDD = (a: -1; b: 1; Kind: sddBii; Complement: False);
begin
  inherited;
  rfcn := arcsin;
  cfcn := carcsin;
  rdom := rdom_arcsin;
end;

{ FCN_arccos }

procedure FCN_arccos.InitNode;
const
  rdom_arccos: TSDD = (a: -1; b: 1; Kind: sddBii; Complement: False);
begin
  inherited;
  rfcn := arccos;
  cfcn := carccos;
  rdom := rdom_arccos;
end;

{ FCN_arctan }

procedure FCN_arctan.InitNode;
begin
  rfcn := arctan;
  cfcn := carctan;
end;

{ FCN_arccot }

procedure FCN_arccot.InitNode;
begin
  rfcn := arccot;
  cfcn := carccot;
end;

{ FCN_arcsec }

procedure FCN_arcsec.InitNode;
const
  rdom_arcsec: TSDD = (a: -1; b: 1; Kind: sddBee; Complement: True);
begin
  rfcn := arcsec;
  cfcn := carcsec;
  rdom := rdom_arcsec;
end;

{ FCN_arccsc }

procedure FCN_arccsc.InitNode;
const
  rdom_arccsc: TSDD = (a: -1; b: 1; Kind: sddBee; Complement: True);
begin
  rfcn := arccsc;
  cfcn := carccsc;
  rdom := rdom_arccsc;
end;

{ FCN_sinh }

procedure FCN_sinh.InitNode;
begin
  rfcn := sinh;
  cfcn := csinh;
end;

{ FCN_cosh }

procedure FCN_cosh.InitNode;
begin
  rfcn := cosh;
  cfcn := ccosh;
end;

{ FCN_tanh }

procedure FCN_tanh.InitNode;
begin
  rfcn := Math.tanh;
  cfcn := ctanh;
end;

{ FCN_coth }

procedure FCN_coth.InitNode;
begin
  rfcn := Math.coth;
  cfcn := ccoth;
end;

{ FCN_sech }

procedure FCN_sech.InitNode;
begin
  rfcn := ASNum.sech;
  cfcn := csech;
end;

{ FCN_csch }

procedure FCN_csch.InitNode;
begin
  rfcn := ASNum.csch;
  cfcn := ccsch;
end;

{ FCN_arcsinh }

procedure FCN_arcsinh.InitNode;
begin
  rfcn := ASNum.arcsinh;
  cfcn := carcsinh;
end;

{ FCN_arccosh }

procedure FCN_arccosh.InitNode;
const
  rdom_arccosh: TSDD = (a: 1; Kind: sddGeq; Complement: False);
begin
  inherited;
  rfcn := arccosh;
  cfcn := carccosh;
  rdom := rdom_arccosh;
end;

{ FCN_arctanh }

procedure FCN_arctanh.InitNode;
const
  rdom_arctanh: TSDD = (a: -1; b: 1; Kind: sddBee; Complement: False);
begin
  inherited;
  rfcn := arctanh;
  cfcn := carctanh;
  rdom := rdom_arctanh;
end;

{ FCN_arccoth }

procedure FCN_arccoth.InitNode;
const
  rdom_arccoth: TSDD = (a: -1; b: 1; Kind: sddBii; Complement: True);
begin
  inherited;
  rfcn := arccoth;
  cfcn := carccoth;
  rdom := rdom_arccoth;
end;

{ FCN_arcsech }

procedure FCN_arcsech.InitNode;
const
  rdom_arcsech: TSDD = (a: 0; b: 1; Kind: sddBei; Complement: False);
begin
  inherited;
  rfcn := arcsech;
  cfcn := carcsech;
  rdom := rdom_arcsech;
end;

{ FCN_arccsch }

procedure FCN_arccsch.InitNode;
begin
  rfcn := ASNum.arccsch;
  cfcn := carccsch;
end;

{ FCN_sinc }

procedure FCN_sinc.InitNode;
begin
  rfcn := sinc;
  cfcn := csinc;
end;

{ FCN_exp }

procedure FCN_exp.InitNode;
begin
  rfcn := exp;
  cfcn := cexp;
end;

{ FCN_ln }

procedure FCN_ln.InitNode;
const
  rdom_ln: TSDD = (a: 0; Kind: sddGt; Complement: False);
begin
  inherited;
  rfcn := ln;
  cfcn := cln;
  rdom := rdom_ln;
end;

{ FCN_log }

procedure FCN_log.InitNode;
const
  rdom_ln: TSDD = (a: 0; Kind: sddGt; Complement: False);
begin
  inherited;
  rfcn := Log10;
  cfcn := clog;
  rdom := rdom_ln;
end;

{ FCN_Floor }

procedure FCN_Floor.SimpleFunction;
var
  X: TASR;
begin
  inherited;
  Args.Extract(X).Close;
  Result := ASOInt(ASNum.Floor64(X));
end;

{ FCN_Ceil }

procedure FCN_Ceil.SimpleFunction;
var
  X: TASR;
begin
  Args.Extract(X).Close;
  Result := ASOInt(ASNum.Ceil64(X));
end;

{ FCN_Round }

procedure FCN_Round.SimpleFunction;
var
  X: TASR;
begin
  Args.Extract(X).Close;
  Result := ASOInt(Round(X));
end;

{ FCN_Trunc }

procedure FCN_Trunc.SimpleFunction;
var
  X: TASR;
begin
  Args.Extract(X).Close;
  Result := ASOInt(Trunc(X));
end;

{ FCN_Frac }

procedure FCN_Frac.InitNode;
begin
  rfcn := frac;
end;

{ FCN_Sgn }

procedure FCN_Sgn.SimpleFunction;
var
  x: TASR;
  z: TASC;
begin
  if Args.PeekAt(0) is TAlgosimComplexNumber then
  begin
    Args.Extract(z).Close;
    Result := ASO(csign(z));
  end
  else
  begin
    Args.Extract(x).Close;
    Result := ASOInt(Sign(x));
  end;
end;

{ FCN_mod }

procedure FCN_mod.SimpleFunction;
var
  A, B: TASI;
  X, Y: TASR;
begin
  if (Args.PeekAt(0) is TAlgosimInteger) and (Args.PeekAt(1) is TAlgosimInteger) then
  begin
    Args.Extract(A).Extract(B).Close;
    Result := ASOInt(ASNum.imod(A, B));
  end
  else
  begin
    Args.Extract(X).Extract(Y).Close;
    Result := ASO(ASNum.rmod(X, Y));
  end;
end;

{ FCN_lcm }

procedure FCN_lcm.SimpleFunction;
var
  Vals: TArray<Int64>;
begin
  Vals := Args.ExtractInt64s;
  Result := ASOInt(ASNum.lcm(Vals));
end;

{ FCN_gcd }

procedure FCN_gcd.SimpleFunction;
var
  Vals: TArray<Int64>;
begin
  Vals := Args.ExtractInt64s;
  Result := ASOInt(ASNum.gcd(Vals));
end;

{ FCN_combinations }

procedure FCN_combinations.SimpleFunction;
var
  n, k: Integer;
  res: TASI;
begin
  Args.Extract(n).Extract(k).Close;
  res := intcombinations(n, k);
  if res <> 0 then
    Result := ASOInt(res)
  else
    Result := ASO(combinations(n, k));
end;

{ FCN_permutations }

procedure FCN_permutations.SimpleFunction;
var
  n, k: Integer;
  res: TASI;
begin
  Args.Extract(n).Extract(k).Close;
  res := intpermutations(n, k);
  if res <> 0 then
    Result := ASOInt(res)
  else
    Result := ASO(permutations(n, k));
end;

{ FCN_IsPrime }

procedure FCN_IsPrime.SimpleFunction;
var
  Arg: TASI;
begin
  Args.Extract(Arg).Close;
  Result := ASO(ASNum.IsPrime(Arg));
end;

{ FCN_NextPrime }

procedure FCN_NextPrime.SimpleFunction;
var
  Arg: TASI;
begin
  Args.Extract(Arg).Close;
  Result := ASOInt(ASNum.NextPrime(Arg));
end;

{ FCN_PrevPrime }

procedure FCN_PrevPrime.SimpleFunction;
var
  Arg: TASI;
begin
  Args.Extract(Arg).Close;
  Result := ASOInt(ASNum.PreviousPrime(Arg));
end;

{ FCN_NthPrime }

procedure FCN_NthPrime.SimpleFunction;
var
  Arg: TASI;
begin
  Args.Extract(Arg).Close;
  if Arg < 0 then
    Arg := 0
  else if Arg > Integer.MaxValue then
  begin
    Result := ASO(failure, 'Cannot test integers this large for primality.');
    Exit;
  end;
  Result := ASOInt(ASNum.NthPrime(Integer(Arg)));
end;

{ FCN_PrimePi }

procedure FCN_PrimePi.SimpleFunction;
var
  Arg: TASI;
begin
  Args.Extract(Arg).Close;
  if Arg < 0 then
    Result := ASOInt(0)
  else if Arg > Integer.MaxValue then
    Result := ASO(failure, 'Cannot test integers this large for primality.')
  else
    Result := ASOInt(ASNum.PrimePi(Arg));
end;

{ FCN_Fibonacci }

procedure FCN_Fibonacci.SimpleFunction;
var
  Arg: TASI;
begin
  Args.Extract(Arg).Close;
  if InRange(Arg, Low(IntFibonaccis), High(IntFibonaccis)) then
    Result := ASOInt(IntFibonaccis[Arg])
  else
    Result := ASO(ASNum.Fibonacci(Arg));
end;

{ FCN_Lucas }

procedure FCN_Lucas.SimpleFunction;
var
  Arg: TASI;
begin
  Args.Extract(Arg).Close;
  if InRange(Arg, Low(IntLucas), High(IntLucas)) then
    Result := ASOInt(IntLucas[Arg])
  else
    Result := ASO(ASNum.Lucas(Arg));
end;

{ FCN_MöbiusMu }

procedure FCN_MöbiusMu.SimpleFunction;
var
  Arg: TASI;
begin
  Args.Extract(Arg).Close;
  Result := ASOInt(ASNum.MöbiusMu(Arg));
end;

{ FCN_Mertens }

procedure FCN_Mertens.SimpleFunction;
var
  Arg: TASI;
begin
  Args.Extract(Arg).Close;
  Result := ASOInt(ASNum.Mertens(Arg));
end;

{ FCN_AreCoprime }

procedure FCN_AreCoprime.SimpleFunction;
var
  Arg1, Arg2: TASI;
begin
  Args.Extract(Arg1).Extract(Arg2).Close;
  Result := ASO(ASNum.coprime(Arg1, Arg2));
end;

{ FCN_Iverson }

procedure FCN_Iverson.SimpleFunction;
var
  Arg: Boolean;
begin
  Args.Extract(Arg).Close;
  Result := ASOInt(ASNum.IversonBracket(Arg));
end;

{ FCN_Kronecker }

procedure FCN_Kronecker.SimpleFunction;
var
  Arg1, Arg2: TASI;
begin
  Args.Extract(Arg1).Extract(Arg2).Close;
  Result := ASOInt(ASNum.KroneckerDelta(Arg1, Arg2));
end;

{ FCN_LegendreSymbol }

procedure FCN_LegendreSymbol.SimpleFunction;
var
  Arg1, Arg2: TASI;
begin
  Args.Extract(Arg1).Extract(Arg2).Close;
  Result := ASOInt(ASNum.LegendreSymbol(Arg1, Arg2));
end;

{ FCN_JacobiSymbol }

procedure FCN_JacobiSymbol.SimpleFunction;
var
  Arg1, Arg2: TASI;
begin
  Args.Extract(Arg1).Extract(Arg2).Close;
  Result := ASOInt(ASNum.JacobiSymbol(Arg1, Arg2));
end;

{ FCN_KroneckerSymbol }

procedure FCN_KroneckerSymbol.SimpleFunction;
var
  Arg1, Arg2: TASI;
begin
  Args.Extract(Arg1).Extract(Arg2).Close;
  Result := ASOInt(ASNum.KroneckerSymbol(Arg1, Arg2));
end;

{ FCN_totient }

procedure FCN_totient.SimpleFunction;
var
  Arg: Integer;
begin
  Args.Extract(Arg).Close;
  Result := ASOInt(ASNum.totient(Arg));
end;

{ FCN_cototient }

procedure FCN_cototient.SimpleFunction;
var
  Arg: Integer;
begin
  Args.Extract(Arg).Close;
  Result := ASOInt(ASNum.cototient(Arg));
end;

{ FCN_PrimeFactors }

procedure FCN_PrimeFactors.SimpleFunction;
var
  Arg: TASI;
begin
  Args.Extract(Arg).Close;
  Result := TAlgosimArray.CreateWithValue(ASNum.PrimeFactors(Arg));
end;

{ FCN_Radical }

procedure FCN_Radical.SimpleFunction;
var
  Arg: TASI;
begin
  Args.Extract(Arg).Close;
  Result := ASOInt(ASNum.Radical(Arg));
end;

{ FCN_IsSquareFree }

procedure FCN_IsSquareFree.SimpleFunction;
var
  Arg: TASI;
begin
  Args.Extract(Arg).Close;
  Result := ASO(ASNum.IsSquareFree(Arg));
end;

{ FCN_Factorize }

procedure FCN_Factorize.SimpleFunction;
var
  Arg: TASI;
begin
  Args.Extract(Arg).Close;
  Result := TAlgosimArray.CreateWithValue(ASNum.factorize(Arg));
end;

{ FCN_FactorizedExpression }

procedure FCN_FactorizedExpression.SimpleFunction;
var
  Arg: TASI;
begin
  Args.Extract(Arg).Close;
  Result := ASO(ASNum.GetFactorizedString(Arg, True));
end;

{ FCN_Divisors }

procedure FCN_Divisors.SimpleFunction;
var
  Arg: TASI;
begin
  Args.Extract(Arg).Close;
  Result := TAlgosimArray.CreateWithValue(ASNum.divisors(Arg));
end;

{ FCN_ContinuedFraction }

procedure FCN_ContinuedFraction.SimpleFunction;
var
  Arg: TAlgosimObject;
  maxlen: Integer;
  cf: TArray<TASI>;
begin

  Args.Extract(Arg).ExtractPos(maxlen, 18).Close;
  if Arg is TAlgosimRationalNumber then
    cf := ASNum.ContinuedFraction(TAlgosimRationalNumber(Arg).Value)
  else if stRationalNumber.MatchingName(Arg) then
    cf := ASNum.ContinuedFraction(ASOToRationalNumber(TAlgosimTypedStructure(Arg)))
  else if Arg is TAlgosimInteger then
    cf := [Arg.ToASI]
  else if Arg is TAlgosimNumber then
    cf := ASNum.ContinuedFraction(Arg.ToASR, maxlen)
  else
    ErrInvalidArguments;

  if Length(cf) > maxlen then
    SetLength(cf, maxlen);

  Result := TAlgosimArray.CreateWithValue(cf);

end;

{ FCN_ToFraction }

procedure FCN_ToFraction.SimpleFunction;
var
  RatParts: TAlgosimTypedStructure;
  Num: TAlgosimNumber;
  CF: TArray<TASI>;
begin

  if (Args.Count <= 1) and not (Args.PeekAt(0) is TAlgosimArray) then
  begin
    if Args.PeekAt(0) is TAlgosimStructure then
    begin
      Args.Extract(RatParts, stRationalNumber);
      Result := ASORat(ASOToRationalNumber(RatParts));
    end
    else
    begin
      Args.Extract(Num);
      Result := ASORat(Num.ToRat);
    end;
  end

  else
  begin
    CF := Args.ExtractInt64s;
    Result := ASORat(ASNum.ContinuedFractionToFraction(CF));
  end;

  if Result is TAlgosimRationalNumber then
  begin
    TAlgosimRationalNumber(Result).NumberFormat := nfFraction;
    TAlgosimRationalNumber(Result).NumberFormatOverride := True;
  end;

end;

{ FCN_ToSymbolicForm }

procedure FCN_ToSymbolicForm.SimpleFunction;
resourcestring
  SNoCloseEnoughSymbolicFormFound = 'No close enough symbolic form found.';

  function GetStr(const AValue: TASR): string;
  var
    SSF: TSimpleSymbolicForm;
  begin
    SSF := ASNum.ToSymbolicForm(AValue);
    if SSF.valid then
      Result := SSF.ToString(Context.FormatOptions)
    else
      Result := SNoCloseEnoughSymbolicFormFound;
  end;

var
  Arg: TAlgosimNumber;
  z: TASC;
begin
  Args.Extract(Arg).Close;
  if Arg.IsComplex then
  begin
    z := Arg.ToASC;
    Result := TAlgosimStructure.CreateWithValue(
      ['Re', 'Im'],
      [ASO(GetStr(z.Re)), ASO(GetStr(z.Im))]
    );
  end
  else
    Result := ASO(GetStr(Arg.ToASR));
end;

{ FCN_erf }

procedure FCN_erf.InitNode;
begin
  rfcn := ASNum.erf;
end;

{ FCN_cerf }

procedure FCN_erfc.InitNode;
begin
  rfcn := ASNum.erfc;
end;

{ FCN_FresnelC }

procedure FCN_FresnelC.InitNode;
begin
  rfcn := ASNum.FresnelC;
end;

{ FCN_FresnelS }

procedure FCN_FresnelS.InitNode;
begin
  rfcn := ASNum.FresnelS;
end;

{ FCN_Si }

procedure FCN_Si.InitNode;
begin
  rfcn := ASNum.Si;
end;

{ FCN_Ci }

procedure FCN_Ci.InitNode;
begin
  rfcn := ASNum.Ci;
end;

{ FCN_Bessel }

procedure FCN_Bessel.SimpleFunction;
var
  N: Integer;
  Arg: TAlgosimNumber;
begin

  Args.Extract(N).Extract(Arg).Close;

  if Arg.IsComplex then
    Result := ASO(ASNum.Bessel(N, Arg.ToASC))
  else
    Result := ASO(ASNum.Bessel(N, Arg.ToASR));

end;

{ FCN_Laguerre }

procedure FCN_Laguerre.SimpleFunction;
var
  N: Integer;
  Arg: TAlgosimNumber;
begin

  Args.Extract(N).Extract(Arg).Close;

  if Arg.IsComplex then
    Result := ASO(ASNum.Laguerre(N, Arg.ToASC))
  else
    Result := ASO(ASNum.Laguerre(N, ARg.ToASR));

end;

{ FCN_Hermite }

procedure FCN_Hermite.SimpleFunction;
var
  N: Integer;
  Arg: TAlgosimNumber;
begin

  Args.Extract(N).Extract(Arg).Close;

  if Arg.IsComplex then
    Result := ASO(ASNum.Hermite(N, Arg.ToASC))
  else
    Result := ASO(ASNum.Hermite(N, Arg.ToASR));

end;

{ FCN_Legendre }

procedure FCN_Legendre.SimpleFunction;
var
  N: Integer;
  Arg: TAlgosimNumber;
begin

  Args.Extract(N).Extract(Arg).Close;

  if Arg.IsComplex then
    Result := ASO(ASNum.Legendre(N, Arg.ToASC))
  else
    Result := ASO(ASNum.Legendre(N, Arg.ToASR));

end;

{ FCN_GammaFunction }

procedure FCN_GammaFunction.InitNode;
begin
  rfcn := ASNum.GammaFunction;
  cfcn := ASNum.GammaFunction;
end;

{ FCN_Chebyshev }

procedure FCN_Chebyshev.SimpleFunction;
var
  N: Integer;
  Arg: TAlgosimNumber;
begin

  Args.Extract(N).Extract(Arg).Close;

  if Arg.IsComplex then
    Result := ASO(ASNum.Chebyshev(N, Arg.ToASC))
  else
    Result := ASO(ASNum.Chebyshev(N, Arg.ToASR));

end;

{ FCN_Bernstein }

procedure FCN_Bernstein.SimpleFunction;
var
  I, N: Integer;
  Arg: TAlgosimNumber;
begin

  Args.Extract(I).Extract(N).Extract(Arg).Close;

  if Arg.IsComplex then
    Result := ASO(ASNum.Bernstein(I, N, Arg.ToASC))
  else
    Result := ASO(ASNum.Bernstein(I, N, Arg.ToASR));

end;

{ FCN_HarmonicNumber }

procedure FCN_HarmonicNumber.SimpleFunction;
var
  Arg: TAlgosimNumber;
  IntVal: TASI;
  X: TASR;
begin
  Args.Extract(Arg).Close;
  if Arg.TryToASI(IntVal) then
    Result := ASO(ASNum.HarmonicNumber(IntVal))
  else
  begin
    X := Arg.ToASR;
    if X > TASI.MaxValue then
      Result := ASO(EulerMascheroni + Ln(X))
    else
      ErrInvalidArguments;
  end;
end;

{ FCN_And }

procedure FCN_And.DoBitwise;
var
  i: Integer;
  Res, Operand: TAlgosimInteger;
begin
  if not EvalChildren(1) then Exit; // 0 already evaluated
  Res := TAlgosimInteger.Create(Children[0].Value);
  Value := Res;
  for i := 1 to ChildCount - 1 do
  begin
    Extract<TAlgosimInteger>(i, Operand);
    Res.Value := Res.Value and Operand.Value;
  end;
end;

procedure FCN_And.DoExecute;
var
  i, h: Integer;
  Operand: TAlgosimBoolean;
begin

  h := Args.Count - 1;

  for i := 0 to h do
  begin

    if not EvalChild(i) then Exit;

    // Bitwise?
    if (i = 0) and (Args.PeekAt(0) is TAlgosimInteger) then
    begin
      DoBitwise;
      Exit;
    end;

    Extract<TAlgosimBoolean>(i, Operand);

    if not Operand.Value or (i = h) then
    begin
      TMover<TAlgosimObject>.Move(Value, Children[i].Value);
      Exit;
    end;

  end;

  Result := ASO(True);

end;

{ FCN_Or }

procedure FCN_Or.DoBitwise;
var
  i: Integer;
  Res, Operand: TAlgosimInteger;
begin
  if not EvalChildren(1) then Exit; // 0 already evaluated
  Res := TAlgosimInteger.Create(Children[0].Value);
  Value := Res;
  for i := 1 to ChildCount - 1 do
  begin
    Extract<TAlgosimInteger>(i, Operand);
    Res.Value := Res.Value or Operand.Value;
  end;
end;

procedure FCN_Or.DoExecute;
var
  i, h: Integer;
  Operand: TAlgosimBoolean;
begin

  h := Args.Count - 1;

  for i := 0 to h do
  begin

    if not EvalChild(i) then Exit;

    // Bitwise?
    if (i = 0) and (Args.PeekAt(0) is TAlgosimInteger) then
    begin
      DoBitwise;
      Exit;
    end;

    Extract<TAlgosimBoolean>(i, Operand);

    if Operand.Value or (i = h) then
    begin
      TMover<TAlgosimObject>.Move(Value, Children[i].Value);
      Exit;
    end;

  end;

  Result := ASO(False);

end;

{ FCN_Not }

procedure FCN_Not.SimpleFunction;
var
  Arg: Boolean;
  IntArg: TASI;
begin
  if Args.PeekAt(0) is TAlgosimInteger then
  begin
    Args.Extract(IntArg).Close;
    Result := ASOInt(not IntArg);
    Exit;
  end;
  Args.Extract(Arg).Close;
  Result := ASO(not Arg);
end;

{ FCN_Xor }

procedure FCN_Xor.SimpleFunction;
var
  Left, Right: Boolean;
  LInt, RInt: TASI;
begin
  // Bitwise?
  if Args.PeekAt(0) is TAlgosimInteger then
  begin
    Args.Extract(LInt).Extract(RInt).Close;
    Result := ASOInt(LInt xor RInt);
    Exit;
  end;
  Args.Extract(Left).Extract(Right).Close;
  Result := ASO(Left xor Right);
end;

{ FCN_Nand }

procedure FCN_Nand.SimpleFunction;
var
  Left, Right: Boolean;
begin
  Args.Extract(Left).Extract(Right).Close;
  Result := ASO(not (Left and Right));
end;

{ FCN_Nor }

procedure FCN_Nor.SimpleFunction;
var
  Left, Right: Boolean;
begin
  Args.Extract(Left).Extract(Right).Close;
  Result := ASO(not (Left or Right));
end;

{ FCN_ImpliesRight }

procedure FCN_ImpliesRight.SimpleFunction;
var
  Left, Right: Boolean;
begin
  Args.Extract(Left).Extract(Right).Close;
  Result := ASO(not Left or Right);
end;

{ FCN_ImpliesLeft }

procedure FCN_ImpliesLeft.SimpleFunction;
var
  Left, Right: Boolean;
begin
  Args.Extract(Left).Extract(Right).Close;
  Result := ASO(not Right or Left);
end;

{ FCN_Equivalent }

procedure FCN_Equivalent.SimpleFunction;
var
  Left, Right: Boolean;
begin
  Args.Extract(Left).Extract(Right).Close;
  Result := ASO(Left = Right);
end;

{ FCN_Equals }

procedure FCN_Equals.SimpleFunction;
var
  Arg1, Arg2: TAlgosimObject;
  LArgs: TArgumentExtractor;
  PrevObj, Obj: TAlgosimObject;
begin

  if Args.Count <> 2 then
  begin
    LArgs := Self.Args;
    if LArgs.ArgExists then
      LArgs := LArgs.Extract(PrevObj);
    while LArgs.ArgExists do
    begin
      LArgs := LArgs.Extract(Obj);
      if not PrevObj.Equals(Obj) then
      begin
        Result := ASO(False);
        Exit;
      end;
      PrevObj := Obj;
    end;
    Result := ASO(True);
    Exit;
  end;

  Args.Extract(Arg1).Extract(Arg2).Close;
  Result := ASO(Arg1.Equals(Arg2));

end;

{ FCN_NotEquals }

procedure FCN_NotEquals.SimpleFunction;
var
  Arg1, Arg2: TAlgosimObject;
begin
  Args.Extract(Arg1).Extract(Arg2).Close;
  Result := ASO(not Arg1.Equals(Arg2));
end;

{ FCN_LessThan }

procedure FCN_LessThan.SimpleFunction;
var
  Arg1, Arg2: TAlgosimObject;
  LArgs: TArgumentExtractor;
  PrevNum, Num: TAlgosimNumber;
begin

  if Args.Count <> 2 then
  begin
    LArgs := Self.Args;
    if LArgs.ArgExists then
      LArgs := LArgs.Extract(PrevNum);
    while LArgs.ArgExists do
    begin
      LArgs := LArgs.Extract(Num);
      if not TAlgosimNumber.LessThan(PrevNum, Num) then
      begin
        Result := ASO(False);
        Exit;
      end;
      PrevNum := Num;
    end;
    Result := ASO(True);
    Exit;
  end;

  Args.Extract(Arg1).Extract(Arg2).Close;

  if (Arg1 is TAlgosimNumber) and (Arg2 is TAlgosimNumber) then
    Result := ASO(TAlgosimNumber.LessThan(TAlgosimNumber(Arg1), TAlgosimNumber(Arg2)))

  else if (Arg1 is TAlgosimRealVector) and (Arg2 is TAlgosimRealVector) then
    Result := ASO(TAlgosimRealVector(Arg1).Value < TAlgosimRealVector(Arg2).Value)

  else if (Arg1 is TAlgosimRealMatrix) and (Arg2 is TAlgosimRealMatrix) then
    Result := ASO(TAlgosimRealMatrix(Arg1).Value < TAlgosimRealMatrix(Arg2).Value)

  else if IsTypedStructure(Arg1, [stDate, stDateTime]) and IsTypedStructure(Arg2, [stDate, stDateTime]) then
    Result :=
      ASO(
        CompareDateTime(
          ASOToDateTime(Arg1),
          ASOToDateTime(Arg2)
        ) = LessThanValue
      )

  else
    ErrInvalidArguments;

end;

{ FCN_LessThanOrEqualTo }

procedure FCN_LessThanOrEqualTo.SimpleFunction;
var
  Arg1, Arg2: TAlgosimObject;
  LArgs: TArgumentExtractor;
  PrevNum, Num: TAlgosimNumber;
begin

  if Args.Count <> 2 then
  begin
    LArgs := Self.Args;
    if LArgs.ArgExists then
      LArgs := LArgs.Extract(PrevNum);
    while LArgs.ArgExists do
    begin
      LArgs := LArgs.Extract(Num);
      if not TAlgosimNumber.LessThanOrEqualTo(PrevNum, Num) then
      begin
        Result := ASO(False);
        Exit;
      end;
      PrevNum := Num;
    end;
    Result := ASO(True);
    Exit;
  end;

  Args.Extract(Arg1).Extract(Arg2).Close;

  if (Arg1 is TAlgosimNumber) and (Arg2 is TAlgosimNumber) then
    Result := ASO(TAlgosimNumber.LessThanOrEqualTo(TAlgosimNumber(Arg1), TAlgosimNumber(Arg2)))

  else if (Arg1 is TAlgosimRealVector) and (Arg2 is TAlgosimRealVector) then
    Result := ASO(TAlgosimRealVector(Arg1).Value <= TAlgosimRealVector(Arg2).Value)

  else if (Arg1 is TAlgosimRealMatrix) and (Arg2 is TAlgosimRealMatrix) then
    Result := ASO(TAlgosimRealMatrix(Arg1).Value <= TAlgosimRealMatrix(Arg2).Value)

  else if IsTypedStructure(Arg1, [stDate, stDateTime]) and IsTypedStructure(Arg2, [stDate, stDateTime]) then
    Result :=
      ASO(
        CompareDateTime(
          ASOToDateTime(Arg1),
          ASOToDateTime(Arg2)
        ) <= EqualsValue
      )

  else
    ErrInvalidArguments;

end;

{ FCN_GreaterThan }

procedure FCN_GreaterThan.SimpleFunction;
var
  Arg1, Arg2: TAlgosimObject;
  IntVal: Integer;
  LArgs: TArgumentExtractor;
  PrevNum, Num: TAlgosimNumber;
begin

  if Args.Count <> 2 then
  begin
    LArgs := Self.Args;
    if LArgs.ArgExists then
      LArgs := LArgs.Extract(PrevNum);
    while LArgs.ArgExists do
    begin
      LArgs := LArgs.Extract(Num);
      if not TAlgosimNumber.GreaterThan(PrevNum, Num) then
      begin
        Result := ASO(False);
        Exit;
      end;
      PrevNum := Num;
    end;
    Result := ASO(True);
    Exit;
  end;

  Args.Extract(Arg1).Extract(Arg2).Close;

  if (Arg1 is TAlgosimNumber) and (Arg2 is TAlgosimNumber) then
    Result := ASO(TAlgosimNumber.GreaterThan(TAlgosimNumber(Arg1), TAlgosimNumber(Arg2)))

  else if (Arg1 is TAlgosimRealVector) and (Arg2 is TAlgosimRealVector) then
    Result := ASO(TAlgosimRealVector(Arg1).Value > TAlgosimRealVector(Arg2).Value)

  else if (Arg1 is TAlgosimRealVector) and (Arg2 is TAlgosimNumber) and Arg2.TryToInt32(IntVal) and (IntVal = 0) then
    Result := ASO(TAlgosimRealVector(Arg1).Value.IsPositive)

  else if (Arg1 is TAlgosimRealMatrix) and (Arg2 is TAlgosimRealMatrix) then
    Result := ASO(TAlgosimRealMatrix(Arg1).Value > TAlgosimRealMatrix(Arg2).Value)

  else if (Arg1 is TAlgosimRealMatrix) and (Arg2 is TAlgosimNumber) and Arg2.TryToInt32(IntVal) and (IntVal = 0) then
    Result := ASO(TAlgosimRealMatrix(Arg1).Value.IsPositive)

  else if IsTypedStructure(Arg1, [stDate, stDateTime]) and IsTypedStructure(Arg2, [stDate, stDateTime]) then
    Result :=
      ASO(
        CompareDateTime(
          ASOToDateTime(Arg1),
          ASOToDateTime(Arg2)
        ) = GreaterThanValue
      )

  else
    ErrInvalidArguments;

end;

{ FCN_GreaterThanOrEqualTo }

procedure FCN_GreaterThanOrEqualTo.SimpleFunction;
var
  Arg1, Arg2: TAlgosimObject;
  IntVal: Integer;
  LArgs: TArgumentExtractor;
  PrevNum, Num: TAlgosimNumber;
begin

  if Args.Count <> 2 then
  begin
    LArgs := Self.Args;
    if LArgs.ArgExists then
      LArgs := LArgs.Extract(PrevNum);
    while LArgs.ArgExists do
    begin
      LArgs := LArgs.Extract(Num);
      if not TAlgosimNumber.GreaterThanOrEqualTo(PrevNum, Num) then
      begin
        Result := ASO(False);
        Exit;
      end;
      PrevNum := Num;
    end;
    Result := ASO(True);
    Exit;
  end;

  Args.Extract(Arg1).Extract(Arg2).Close;

  if (Arg1 is TAlgosimNumber) and (Arg2 is TAlgosimNumber) then
    Result := ASO(TAlgosimNumber.GreaterThanOrEqualTo(TAlgosimNumber(Arg1), TAlgosimNumber(Arg2)))

  else if (Arg1 is TAlgosimRealVector) and (Arg2 is TAlgosimRealVector) then
    Result := ASO(TAlgosimRealVector(Arg1).Value >= TAlgosimRealVector(Arg2).Value)

  else if (Arg1 is TAlgosimRealVector) and (Arg2 is TAlgosimNumber) and Arg2.TryToInt32(IntVal) and (IntVal = 0) then
    Result := ASO(TAlgosimRealVector(Arg1).Value.IsNonNegative)

  else if (Arg1 is TAlgosimRealMatrix) and (Arg2 is TAlgosimRealMatrix) then
    Result := ASO(TAlgosimRealMatrix(Arg1).Value >= TAlgosimRealMatrix(Arg2).Value)

  else if (Arg1 is TAlgosimRealMatrix) and (Arg2 is TAlgosimNumber) and Arg2.TryToInt32(IntVal) and (IntVal = 0) then
    Result := ASO(TAlgosimRealMatrix(Arg1).Value.IsNonNegative)

  else if IsTypedStructure(Arg1, [stDate, stDateTime]) and IsTypedStructure(Arg2, [stDate, stDateTime]) then
    Result :=
      ASO(
        CompareDateTime(
          ASOToDateTime(Arg1),
          ASOToDateTime(Arg2)
        ) >= EqualsValue
      )

  else
    ErrInvalidArguments;

end;

{ FCN_Dim }

procedure FCN_Dim.DoExecute;
var
  Arg: TAlgosimVector;
begin
  CheckNumArgs(1);
  if not ExtractRef<TAlgosimVector>(0, Arg) then Exit;
  Result := ASOInt(Arg.Dimension);
end;

{ FCN_Size }

procedure FCN_Size.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASOSize(Arg.PlanarExtent);
end;

{ FCN_Width }

procedure FCN_Width.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASOInt(Arg.PlanarExtent.cx);
end;

{ FCN_Height }

procedure FCN_Height.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASOInt(Arg.PlanarExtent.cy);
end;

{ FCN_Subscript }

function FCN_Subscript.BuildLValue(LValueData: TLValueData): Boolean;
var
  i: Integer;
begin
  Result := ChildCount >= 2;
  if Result then
  begin
    for i := 1 to ChildCount - 1 do
    begin
      Children[i].Evaluate;
      if IsControl(Children[i].Value) then
        Exit(False);
    end;
    if ChildCount = 2 then
      LValueData.Add(TLValuePathItem.Create(Children[1].Value))
    else
    begin
      // emulate an array of integers, so you can write A[1, 2] instead of A['(1, 2)]
      FreeAndNil(FEquivArray);
      FEquivArray := TAlgosimArray.Create;
      for i := 1 to ChildCount - 1 do
        FEquivArray.Add(Children[i].Value.Clone);
      LValueData.Add(TLValuePathItem.Create(FEquivArray));
    end;
    Result := Children[0].BuildLValue(LValueData);
  end;
end;

destructor FCN_Subscript.Destroy;
begin
  FreeAndNil(FEquivArray);
  inherited;
end;

procedure FCN_subscript.DoExecute;
var
  Obj, Idx: TAlgosimObject;
begin
  CheckNumArgsAtLeast(2);
  if not ExtractRef(0, Obj) then Exit;
  if not EvalChildren(1) then Exit;
  if Args.Count = 2 then
  begin
    Args.Skip.Extract(Idx);
    Result := Obj.GetSubscriptedValue(TSubscript.Create(Idx));
  end
  else
  begin
    // emulate an array of integers, so you can write A[1, 2] instead of A['(1, 2)]
    Idx := TAlgosimArray.CreateWithValue(Args.Skip.ExtractInt64s);
    try
      Result := Obj.GetSubscriptedValue(TSubscript.Create(Idx));
    finally
      Idx.Free;
    end;
  end;
end;

function FCN_Subscript.LValuePart: Boolean;
begin
  Result := True;
end;

{ FCN_AccessMember }

function FCN_AccessMember.BuildLValue(LValueData: TLValueData): Boolean;
begin
  Result := (ChildCount = 2) and IsSymbol(Children[1]);
  if Result then
  begin
    LValueData.Add(TLValuePathItem.Create(TASSymbolExprNode(Children[1]).Symbol));
    Result := Children[0].BuildLValue(LValueData);
  end;
end;

procedure FCN_AccessMember.DoExecute;
var
  Struct: TAlgosimStructure;
  MbrName: string;
begin

  CheckNumArgs(2);

  if not TryLValueFetch then
  begin
    if not EvalChild(0) then Exit;
    CheckSymbol(1);
    Args.Extract(Struct);
    MbrName := TASSymbolExprNode(Children[1]).Symbol;
    Result := Struct[MbrName];
    Struct.Release(MbrName);
  end;

end;

function FCN_AccessMember.LValuePart: Boolean;
begin
  Result := True;
end;

{ FCN_norm }

procedure FCN_Norm.SimpleFunction;
var
  Arg: TAlgosimNumericEntity;
  Kind: string;
  Param: Integer;
begin
  Args.Extract(Arg).Extract(Kind, 'Euclidean').Extract(Param, 2).Close;
  Result := ASO(Arg.Norm(TNormType.FromString(Kind), Param, QuitPauseCheck));
end;

{ FCN_NormSquared }

procedure FCN_NormSquared.SimpleFunction;
var
  Arg: TAlgosimNumericEntity;
begin
  Args.Extract(Arg).Close;
  Result := Arg.NormSquared;
end;

{ FCN_Normalized }

procedure FCN_Normalized.SimpleFunction;
var
  Arg: TAlgosimVector;
begin
  Args.Extract(Arg).Close;
  Result := Arg.NormalizedIfNonzero;
end;

{ FCN_First }

function FCN_First.BuildLValue(LValueData: TLValueData): Boolean;
begin
  Result := ChildCount = 1;
  if Result then
  begin
    LValueData.Add(TLValuePathItem.Create(skFirst));
    Result := Children[0].BuildLValue(LValueData);
  end;
end;

procedure FCN_First.DoExecute;
var
  Obj: TAlgosimObject;
  N: Integer;
begin

  CheckNumArgs([1, 2]);

  if Args.Count = 1 then
  begin
    if not ExtractRef(0, Obj) then Exit;
    Result := Obj.Values[1];
  end
  else
  begin
    if not EvalChild(1) then Exit;
    Args.Skip.ExtractNonNeg(N).Close;

    if TryExtractStoreRef(0, Obj) then
      Result := Obj.First(N) // don't modify!
    else
    begin
      if not EvalChild(0) then Exit;
      if Args.PeekAt(0).IsPlanarContainer then
        Result := Args.PeekAt(0).First(N)
      else
      begin
        Args.MoveObject(Value);
        Value.Truncate(N);
      end;
    end;
  end;

end;

function FCN_First.LValuePart: Boolean;
begin
  Result := True;
end;

{ FCN_Last }

function FCN_Last.BuildLValue(LValueData: TLValueData): Boolean;
begin
  Result := ChildCount = 1;
  if Result then
  begin
    LValueData.Add(TLValuePathItem.Create(skLast));
    Result := Children[0].BuildLValue(LValueData);
  end;
end;

procedure FCN_Last.DoExecute;
var
  Obj: TAlgosimObject;
  N: Integer;
begin

  CheckNumArgs([1, 2]);

  if Args.Count = 1 then
  begin
    if not ExtractRef(0, Obj) then Exit;
    Result := Obj.Values[-1];
  end
  else
  begin
    if not EvalChild(1) then Exit;
    Args.Skip.ExtractNonNeg(N).Close;

    if TryExtractStoreRef(0, Obj) then
      Result := Obj.Last(N) // don't modify!
    else
    begin
      if not EvalChild(0) then Exit;
      if Args.PeekAt(0).IsPlanarContainer then
        Result := Args.PeekAt(0).Last(N)
      else
      begin
        Args.MoveObject(Value);
        Value.RemoveFirst(Value.ValueCount - N);
      end;
    end;
  end;

end;

function FCN_Last.LValuePart: Boolean;
begin
  Result := True;
end;

{ FCN_Part }

procedure FCN_Part.DoExecute;
var
  Obj: TAlgosimObject;
  Ranges, Ranges2: TArray<TRange>;
begin

  CheckNumArgs([2, 3]);
  if not ExtractRef(0, Obj) then Exit;
  if not EvalChildren(1) then Exit;

  case Args.Count - 1 of
    1:
      begin
        Args.Skip.Extract(Ranges).Close;
        Result := Obj.Part(Ranges)
      end;
    2:
      begin
        Args.Skip.Extract(Ranges).Extract(Ranges2).Close;
        Result := Obj.Part2d(Ranges, Ranges2);
      end;
  else
    ErrInvalidArguments;
  end;

end;

{ FCN_Range }

procedure FCN_Range.SimpleFunction;
var
  From, &To, Step: Integer;
begin
  Args.Extract(From).Extract(&To, From).Extract(Step, 1).Close;
  Result := ASOIntRange(From, &To, Step);
end;

{ FCN_Sort }

procedure FCN_Sort.ChooseComparer(const AStr: string);
begin
  if AStr = 'standard order' then
    rcmp := TASRComparer.StandardOrder
  else if AStr = 'standard order descending' then
    rcmp := TASRComparer.StandardOrderDescending
  else if AStr = 'absolute value' then
    rcmp := TASRComparer.AbsoluteValue
  else if AStr = 'absolute value descending' then
    rcmp := TASRComparer.AbsoluteValueDescending
  else if AStr = 'real and imaginary parts' then
    ccmp := TASCComparer.ReIm
  else if AStr = 'real and imaginary parts descending' then
    ccmp := TASCComparer.ReImDescending
  else if AStr = 'modulus' then
    ccmp := TASCComparer.Modulus
  else if AStr = 'modulus descending' then
    ccmp := TASCComparer.ModulusDescending
  else if AStr = 'argument' then
    ccmp := TASCComparer.Argument
  else if AStr = 'argument descending' then
    ccmp := TASCComparer.ArgumentDescending
  else if AStr = 'modulus argument' then
    ccmp := TASCComparer.ModulusArgument
  else if AStr = 'modulus argument descending' then
    ccmp := TASCComparer.ModulusArgumentDescending
  else
    raise EInvArgs.CreateFmt(SUnknownComparer, [AStr]);
end;

procedure FCN_Sort.SimpleFunction;
var
  CmpName: string;
begin
  Args.MoveObject(Value).Extract(CmpName, '').Close;
  if CmpName.IsEmpty then
  begin
    if asoComplex in Value.ClassFlags then
      raise Exception.Create('No comparison method specified.')
    else
      Value.Sort
  end
  else
  begin
    ChooseComparer(CmpName.ToLower);
    if Assigned(ccmp) then
      Value.Sort(ccmp)
    else if Assigned(rcmp) then
      Value.Sort(rcmp)
    else
      ErrInternal;
  end;
end;

{ FCN_CustomSort }

procedure FCN_CustomSort.DoExecute;
var
  SymLeft, SymRight: TList<TASExprNode>;
begin

  CheckNumArgs(2);

  if not EvalChild(0) then Exit;
  Args.MoveObject(Value);

  SymLeft := TList<TASExprNode>.Create;
  try
    SymRight := TList<TASExprNode>.Create;
    try

      FindSymbols(Children[1], 'left', SymLeft);
      FindSymbols(Children[1], 'right', SymRight);

      Value.SafeSort(TComparer<TAlgosimObject>.Construct(
        function(const Left, Right: TAlgosimObject): Integer
        var
          res: TAlgosimObject;
          cmpres: TASR;
        begin
          PopulateSymbols(SymLeft, Left.Clone);
          PopulateSymbols(SymRight, Right.Clone);
          Children[1].Evaluate;
          res := Children[1].Value;
          CheckFailure(res);
          if res is TAlgosimInteger then
            Result := Sign(TAlgosimInteger(res).Value)
          else if (res is TAlgosimNumber) and res.TryToASR(cmpres) then
            Result := Sign(cmpres)
          else
            raise EAlgosimObjectException.CreateFmt(SComparerDidntReturnReal, [res.TypeName]);
        end
        ));

    finally
      SymRight.Free;
    end;
  finally
    SymLeft.Free;
  end;

end;

{ FCN_Shuffle }

procedure FCN_Shuffle.SimpleFunction;
begin
  Args.MoveObject<TAlgosimObject>(Value).Close;
  Result.Shuffle;
end;

{ FCN_Reverse }

procedure FCN_Reverse.SimpleFunction;
begin
  Args.MoveObject<TAlgosimObject>(Value).Close;
  Result.Reverse;
end;

{ FCN_Unique }

procedure FCN_Unique.SimpleFunction;
var
  Obj: TAlgosimObject;
  Eps: TASR;
begin
  CheckNumArgs([1, 2]);
  case Args.Count of
    1:
      begin
        Args.Extract(Obj).Close;
        Result := Obj.RemoveDuplicates;
      end;
    2:
      begin
        Args.Extract(Obj).ExtractNonNeg(Eps).Close;
        Result := Obj.RemoveDuplicatesEps(Eps);
      end;
  else
    ErrInvalidArguments;
  end;
end;

{ FCN_AdjUnique }

procedure FCN_AdjUnique.SimpleFunction;
var
  Obj: TAlgosimObject;
  Eps: TASR;
begin
  CheckNumArgs([1, 2]);
  case Args.Count of
    1:
      begin
        Args.Extract(Obj).Close;
        Result := Obj.RemoveAdjacentDuplicates;
      end;
    2:
      begin
        Args.Extract(Obj).ExtractNonNeg(Eps).Close;
        Result := Obj.RemoveAdjacentDuplicatesEps(Eps);
      end;
  else
    ErrInvalidArguments;
  end;
end;

{ FCN_Frequencies }

procedure FCN_Frequencies.SimpleFunction;
var
  Obj: TAlgosimObject;
  Eps: TASR;
begin
  CheckNumArgs([1, 2]);
  case Args.Count of
    1:
      begin
        Args.Extract(Obj).Close;
        Result := Obj.Frequencies;
      end;
    2:
      begin
        Args.Extract(Obj).ExtractNonNeg(Eps).Close;
        Result := Obj.FrequenciesEps(Eps);
      end;
  else
    ErrInvalidArguments;
  end;
end;

{ FCN_CollapseSequences }

procedure FCN_CollapseSequences.SimpleFunction;
var
  Obj: TAlgosimObject;
  Eps: TASR;
begin
  CheckNumArgs([1, 2]);
  case Args.Count of
    1:
      begin
        Args.Extract(Obj).Close;
        Result := Obj.CollapseSequences;
      end;
    2:
      begin
        Args.Extract(Obj).ExtractNonNeg(Eps).Close;
        Result := Obj.CollapseSequencesEps(Eps);
      end;
  else
    ErrInvalidArguments;
  end;
end;

{ FCN_ZeroVector }

procedure FCN_ZeroVector.SimpleFunction;
var
  Dim: Integer;
begin
  Args.ExtractPos(Dim).Close;
  Result := ASO(ZeroVector(Dim));
end;

{ FCN_ComplexZeroVector }

procedure FCN_ComplexZeroVector.SimpleFunction;
var
  Dim: Integer;
begin
  Args.ExtractPos(Dim).Close;
  Result := ASO(ComplexZeroVector(Dim));
end;

{ FCN_RandomVector }

procedure FCN_RandomVector.SimpleFunction;
var
  Dim: Integer;
begin
  Args.ExtractPos(Dim).Close;
  Result := ASO(RandomVector(Dim));
end;

{ FCN_RandomIntVector }

procedure FCN_RandomIntVector.SimpleFunction;
var
  Dim, A, B: Integer;
begin
  Args.ExtractPos(Dim).Extract(A).Extract(B).Close;
  if A >= B then
    raise EInvArgs.Create('The set of possible values is empty.');
  Result := ASO(RandomIntVector(Dim, A, B));
end;

{ FCN_RandomSignedVector }

procedure FCN_RandomSignedVector.SimpleFunction;
var
  Dim: Integer;
begin
  Args.ExtractPos(Dim).Close;
  Result := ASO(RandomVectorWithSigns(Dim));
end;

{ FCN_BasisVector }

procedure FCN_BasisVector.SimpleFunction;
var
  Dim, Index: Integer;
begin
  Args.ExtractPos(Dim).ExtractPos(Index).Close;
  Result := ASO(UnitVector(Dim, Index - 1));
end;

{ FCN_SequenceVector }

procedure FCN_SequenceVector.SimpleFunction;
var
  Start, &End, Step: Integer;
  A: TArray<TASI>;
begin

  if Args.Count = 1 then
  begin
    Start := 1;
    Args.ExtractPos(&End).Close;
    A := CreateIntSequence64(Start, &End);
  end
  else
  begin
    Args.Extract(Start).Extract(&End).ExtractPos(Step, 1).Close;
    A := CreateIntSequence64(Start, &End, Step);
  end;

  Result := ASO(TRealVector.Create(Int64ArrToRealArr(A)));

end;

{ FCN_SequenceList }

procedure FCN_SequenceList.SimpleFunction;
var
  Start, &End, Step: Integer;
  A: TArray<TASI>;
begin

  if Args.Count = 1 then
  begin
    Start := 1;
    Args.ExtractPos(&End).Close;
    A := CreateIntSequence64(Start, &End);
  end
  else
  begin
    Args.Extract(Start).Extract(&End).ExtractPos(Step, 1).Close;
    A := CreateIntSequence64(Start, &End, Step);
  end;

  Result := TAlgosimArray.CreateWithValue(A);

end;

{ TIntervalFunction }

procedure TIntervalFunction.SimpleFunction;
var
  a, b, b′, δ, t: TASR;
  L: TList<TASR>;
begin

  Args.Extract(a).Extract(b).ExtractPos(δ, 0).Close;

  if (a > b) or (a = b) and Openinterval then
  begin
    Result := TAlgosimArray.Create;
    Exit;
  end;

  if a = b then
  begin
    Result := TAlgosimArray.CreateWithValue([a]);
    Exit;
  end;

  if δ = 0 then
    δ := (b - a) / 1000;

  if OpenInterval then
  begin
    a := a + δ;
    b := b - δ;
  end;

  L := TList<TASR>.Create;
  try
    L.Capacity := Trunc((b - a) / δ) + 1;
    t := a;
    b′ := b + δ / 1000;    
    while t <= b′ do
    begin    
      L.Add(t);
      t := t + δ;
    end;
    if (L.Count > 0) and (L.Last > b) then
      L[L.Count - 1] := b;
    Result := TAlgosimArray.CreateWithValue(L.ToArray);
  finally
    L.Free;
  end;
  
end;

{ FCN_ClosedInterval }

procedure FCN_ClosedInterval.InitNode;
begin
  inherited;
  OpenInterval := False;
end;


{ FCN_OpenInterval }

procedure FCN_OpenInterval.InitNode;
begin
  inherited;
  OpenInterval := True;
end;

{ FCN_Random }

function FCN_Random.BuildLValue(LValueData: TLValueData): Boolean;
begin
  Result := ChildCount = 1;
  if Result then
  begin
    LValueData.Add(TLValuePathItem.Create(skRandom));
    Result := Children[0].BuildLValue(LValueData);
  end;
end;

procedure FCN_Random.DoExecute;
var
  Obj: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Obj) then Exit;
  Result := Obj.Random;
end;

function FCN_Random.LValuePart: Boolean;
begin
  Result := True;
end;

{ FCN_RandomInt }

procedure FCN_RandomInt.SimpleFunction;
var
  A, B: Integer;
begin

  if Args.Count = 1 then
  begin
    Args.ExtractPos(A).Close;
    Result := ASOInt(System.Random(A));
  end
  else
  begin
    Args.Extract(A).Extract(B).Close;
    if A >= B then
      raise EInvArgs.Create('The set of possible values is empty.');
    Result := ASOInt(RandomRange(A, B));
  end;

end;

{ FCN_RandomReal }

procedure FCN_RandomReal.SimpleFunction;
var
  A, B: TASR;
begin

  if Args.Count = 0 then
    Result := ASO(System.Random)
  else if Args.Count = 1 then
  begin
    Args.Extract(A).Close;
    Result := ASO(A * System.Random);
  end
  else
  begin
    Args.Extract(A).Extract(B).Close;
    Result := ASO(A + (B - A) * System.Random);
  end;

end;

{ FCN_SetRandomSeed }

procedure FCN_SetRandomSeed.SimpleFunction;
var
  Arg: Integer;
begin
  Args.Extract(Arg).Close;
  RandSeed := Arg;
  Result := ASO(success);
end;

{ FCN_Randomize }

procedure FCN_Randomize.SimpleFunction;
begin
  Args.Close;
  Randomize;
  Result := ASO(success);
end;

{ TASContainerFunction }

function __max_int(const A, B: TASI): TASI;
begin
  if A > B then
    Result := A
  else
    Result := B;
end;

function __min_int(const A, B: TASI): TASI;
begin
  if A < B then
    Result := A
  else
    Result := B;
end;

function __max_float(const A, B: TASR): TASR;
begin
  if A > B then
    Result := A
  else
    Result := B;
end;

function __min_float(const A, B: TASR): TASR;
begin
  if A < B then
    Result := A
  else
    Result := B;
end;

procedure TASContainerFunction.DoExecute;
const
  ARG_INDEX_EXPRESSION = 0;
  ARG_INDEX_SYMBOL = 1;
  ARG_INDEX_LOWER_BOUND = 2;
  ARG_INDEX_UPPER_BOUND = 3;
var
  i: Integer;
  k, m, n: TASI;
  Obj: TAlgosimObject;
  symbol: string;
  symbols: TList<TASExprNode>;
  list: TAlgosimArray;
  x, y: TASR;
  ifcn: function(const A, B: TASI): TASI;
  rfcn: function(const A, B: TASR): TASR;
begin

  CheckNumArgs([1, 2, 4]);

  if Args.Count = 1 then
  begin
    if not ExtractRef(0, Obj) then Exit;
    fcn(Obj);
  end

  else if (Args.Count = 2) and ((Self is FCN_Min) or (Self is FCN_Max)) then // special case: allow min(x, y) and max(x, y)
  begin

    if not EvalChildren then Exit;

    if Self is FCN_Min then
    begin
      ifcn := __min_int;
      rfcn := __min_float;
    end
    else if Self is FCN_Max then
    begin
      ifcn := __max_int;
      rfcn := __max_float;
    end
    else
      ErrInternal;

    if (Args.PeekAt(0) is TAlgosimInteger) and (Args.PeekAt(1) is TAlgosimInteger) then
    begin
      Args.Extract(m).Extract(n).Close;
      Result := ASOInt(ifcn(m, n));
    end
    else
    begin
      Args.Extract(x).Extract(y).Close;
      Result := ASO(rfcn(x, y));
    end;

  end

  else if Args.Count = 4 then
  begin

    for i := ARG_INDEX_LOWER_BOUND to ARG_INDEX_UPPER_BOUND do
      if not EvalChild(i) then Exit;

    Args.Skip.Skip.Extract(m).Extract(n).Close;

    CheckSymbol(ARG_INDEX_SYMBOL);
    symbol := TASSymbolExprNode(Children[ARG_INDEX_SYMBOL]).Symbol;

    symbols := TList<TASExprNode>.Create;
    try
      FindSymbols(Self.Children[ARG_INDEX_EXPRESSION], symbol, symbols);
      list := TAlgosimArray.Create;
      try
        if n - m + 1 > Integer.MaxValue then
          raise Exception.Create('Too many values for the index variable.');
        list.Capacity := Max(0, n - m + 1);
        for k := m to n do
        begin
          PopulateSymbols(symbols, ASOInt(k));
          Children[ARG_INDEX_EXPRESSION].Evaluate;
          if IsControl(Children[ARG_INDEX_EXPRESSION].Value) then
          begin
            TMover<TAlgosimObject>.Move(Value, Children[ARG_INDEX_EXPRESSION].Value);
            Exit;
          end;
          list.Add(Children[ARG_INDEX_EXPRESSION].Value.Clone);
        end;
        fcn(list);
      finally
        list.Free;
      end;
    finally
      symbols.Free;
    end;

  end

  else
    ErrInvalidArguments;

end;

{ FCN_Sum }

procedure FCN_Sum.fcn(AObject: TAlgosimObject);
begin
  Result := AObject.N_sum;
end;

{ FCN_Product }

procedure FCN_Product.fcn(AObject: TAlgosimObject);
begin
  Result := AObject.N_product;
end;

{ FCN_Min }

procedure FCN_Min.fcn(AObject: TAlgosimObject);
begin
  Result := AObject.N_min;
end;

{ FCN_Max }

procedure FCN_Max.fcn(AObject: TAlgosimObject);
begin
  Result := AObject.N_max;
end;

{ FCN_ArithmeticMean }

procedure FCN_ArithmeticMean.fcn(AObject: TAlgosimObject);
begin
  Result := AObject.N_ArithmeticMean;
end;

{ FCN_GeometricMean }

procedure FCN_GeometricMean.fcn(AObject: TAlgosimObject);
begin
  Result := AObject.N_GeometricMean;
end;

{ FCN_HarmonicMean }

procedure FCN_HarmonicMean.fcn(AObject: TAlgosimObject);
begin
  Result := AObject.N_HarmonicMean;
end;

{ TASContainerPredicateFunction }

procedure TASContainerPredicateFunction.DoExecute;
var
  Obj: TAlgosimObject;
  Predicate: TAlgosimFunctionObject;
begin
  CheckNumArgs(2);
  if not ExtractRef(0, Obj) then Exit;
  if not EvalChild(1) then Exit;
  Args(1).Extract(Predicate);
  fcn(Obj,
    function(AObject: TAlgosimObject): Boolean
    var
      res: TAlgosimObject;
    begin
      res := Predicate.Execute(Context, [AObject], False);
      try
        if res is TAlgosimBoolean then
          Result := TAlgosimBoolean(res).Value
        else
          raise EAlgosimObjectException.CreateFmt(SPredicateDidntReturnBool, [res.TypeName]);
      finally
        res.Free;
      end;
    end);
end;

{ FCN_Count }

procedure FCN_Count.DoExecute;
var
  Obj, Value: TAlgosimObject;
  Predicate: TAlgosimFunctionObject;
  Eps: TASR;
begin

  CheckNumArgs([2, 3]);
  if not ExtractRef(0, Obj) then Exit;
  if not EvalChildren(1) then Exit;

  if Args.PeekAt(1) is TAlgosimFunctionObject then
  begin
    Args.Skip.Extract(Predicate).Close;
    Result := ASOInt(Obj.Count(
      function(AObject: TAlgosimObject): Boolean
      var
        res: TAlgosimObject;
      begin
        res := Predicate.Execute(Context, [AObject], False);
        try
          if res is TAlgosimBoolean then
            Result := TAlgosimBoolean(res).Value
          else
            raise EAlgosimObjectException.CreateFmt(SPredicateDidntReturnBool, [res.TypeName]);
        finally
          res.Free;
        end;
      end
    ))
  end
  else
  begin
    case Args.Count of
      2:
        begin
          Args.Skip.Extract(Value).Close;
          Result := ASOInt(Obj.CountValue(Value));
        end;
      3:
        begin
          Args.Skip.Extract(Value).ExtractNonNeg(Eps).Close;
          Result := ASOInt(Obj.CountValueEps(Value, Eps));
        end;
    else
      ErrInvalidArguments;
    end;
  end;

end;

{ FCN_Contains }

procedure FCN_Contains.DoExecute;
var
  Obj, Value: TAlgosimObject;
  Eps: TASR;
begin
  CheckNumArgs([2, 3]);
  if not ExtractRef(0, Obj) then Exit;
  if not EvalChildren(1) then Exit;
  case Args.Count of
    2:
      begin
        Args.Skip.Extract(Value).Close;
        Result := ASO(Obj.Contains(Value));
      end;
    3:
      begin
        Args.Skip.Extract(Value).ExtractNonNeg(Eps).Close;
        Result := ASO(Obj.ContainsEps(Value, Eps));
      end;
  else
    ErrInvalidArguments;
  end;
end;

{ FCN_Exists }

procedure FCN_Exists.fcn(AObject: TAlgosimObject;
  APred: TASOPredicate);
begin
  Result := ASO(AObject.Exists(APred));
end;

{ FCN_ExistsUnique }

procedure FCN_ExistsUnique.fcn(AObject: TAlgosimObject;
  APred: TASOPredicate);
begin
  Result := ASO(AObject.ExistsUnique(APred));
end;

{ FCN_ForAll }

procedure FCN_ForAll.fcn(AObject: TAlgosimObject;
  APred: TASOPredicate);
begin
  Result := ASO(AObject.ForAll(APred));
end;

{ FCN_IndicesOf }

procedure FCN_IndicesOf.DoExecute;
var
  Obj, Value: TAlgosimObject;
  Predicate: TAlgosimFunctionObject;
  Eps: TASR;
begin

  CheckNumArgs([2, 3]);
  if not ExtractRef(0, Obj) then Exit;
  if not EvalChildren(1) then Exit;

  if Args.PeekAt(1) is TAlgosimFunctionObject then
  begin
    Args.Skip.Extract(Predicate).Close;
    Result := Obj.IndicesOf(
      function(AObject: TAlgosimObject): Boolean
      var
        res: TAlgosimObject;
      begin
        res := Predicate.Execute(Context, [AObject], False);
        try
          if res is TAlgosimBoolean then
            Result := TAlgosimBoolean(res).Value
          else
            raise EAlgosimObjectException.CreateFmt(SPredicateDidntReturnBool, [res.TypeName]);
        finally
          res.Free;
        end;
      end
    )
  end
  else
  begin
    case Args.Count of
      2:
        begin
          Args.Skip.Extract(Value).Close;
          Result := Obj.IndicesOfValue(Value);
        end;
      3:
        begin
          Args.Skip.Extract(Value).ExtractNonNeg(Eps).Close;
          Result := Obj.IndicesOfValueEps(Value, Eps);
        end;
    else
      ErrInvalidArguments;
    end;
  end;

end;

{ FCN_Filter }

procedure FCN_Filter.fcn(AObject: TAlgosimObject;
  APred: TASOPredicate);
begin
  Result := AObject.Filter(APred);
end;

{ FCN_Pick }

procedure FCN_Pick.DoExecute;
var
  Obj: TAlgosimObject;
  Predicate: TAlgosimFunctionObject;
  Level: Integer;
begin
  CheckNumArgs([2, 3]);
  if not ExtractRef(0, Obj) then Exit;
  if not EvalChildren(1) then Exit;
  Args
    .Skip
    .Extract(Predicate)
    .ExtractPos(Level, 1)
    .Close;
  Value := Obj.Pick(
    function(AObject: TAlgosimObject): Boolean
    var
      res: TAlgosimObject;
    begin
      res := Predicate.Execute(Context, [AObject], False);
      try
        if res is TAlgosimBoolean then
          Result := TAlgosimBoolean(res).Value
        else
          raise EAlgosimObjectException.CreateFmt(SPredicateDidntReturnBool, [res.TypeName]);
      finally
        res.Free;
      end;
    end,
    Level);
end;

{ FCN_PickRecursive }

procedure FCN_PickRecursive.fcn(AObject: TAlgosimObject;
  APred: TASOPredicate);
begin
  Result := AObject.PickRecursive(APred);
end;

{ FCN_Apply }

procedure FCN_Apply.SimpleFunction;
var
  Fcn: TAlgosimFunctionObject;
  Level: Integer;
  &Set: TAlgosimSet;
  i: Integer;
begin

  if Args.PeekAt(0) is TAlgosimSet then
  begin
    // sets don't support the Apply method (cannot simply replace
    // elements in-place: that might create a set with duplicate elements)
    Args.Extract(&Set).Extract(Fcn).Close; // for sets, we don't support the Level argument for simplicity (again, by altering the set's elements, the parent set might end up with duplicate elements)
    Result := TAlgosimSet.Create;
    Result.Capacity := &Set.Capacity;
    for i := 1 to &Set.ElementCount do
      Result.AddElement(Fcn.Execute(Context, [&Set.Elements[i]], False));
    Exit;
  end;

  Args.MoveObject(Value).Extract(Fcn).ExtractPos(Level, 1).Close;
  Value.Apply(
    function(AObject: TAlgosimObject): TAlgosimObject
    begin
      Result := Fcn.Execute(Context, [AObject], False);
    end,
    nil,
    Level
  );

end;

{ FCN_ApplyIf }

procedure FCN_ApplyIf.SimpleFunction;
var
  Pred, Fcn: TAlgosimFunctionObject;
  Level: Integer;
begin
  Args.MoveObject(Value).Extract(Pred).Extract(Fcn).ExtractPos(Level, 1).Close;
  Value.Apply(
    function(AObject: TAlgosimObject): TAlgosimObject
    begin
      Result := Fcn.Execute(Context, [AObject], False);
    end,
    function(AObject: TAlgosimObject): Boolean
    var
      res: TAlgosimObject;
    begin
      res := Pred.Execute(Context, [AObject], False);
      try
        if res is TAlgosimBoolean then
          Result := TAlgosimBoolean(res).Value
        else
          raise EAlgosimObjectException.CreateFmt(SPredicateDidntReturnBool, [res.TypeName]);
      finally
        res.Free;
      end;
    end,
    Level
  );
end;

{ FCN_ReplaceAll }

procedure FCN_ReplaceAll.SimpleFunction;
var
  OldVal, NewVal: TAlgosimObject;
  Level: Integer;
begin
  Args
    .MoveObject(Value)
    .Extract(OldVal)
    .Extract(NewVal)
    .ExtractPos(Level, 1)
    .Close;
  Value.Replace(OldVal, NewVal, Level);
end;

{ FCN_ReplaceIf }

procedure FCN_ReplaceIf.SimpleFunction;
var
  NewVal: TAlgosimObject;
  Pred: TAlgosimFunctionObject;
  Level: Integer;
begin
  Args
    .MoveObject(Value)
    .Extract(Pred)
    .Extract(NewVal)
    .ExtractPos(Level, 1)
    .Close;
  Value.Replace(
    function(AObject: TAlgosimObject): Boolean
    var
      res: TAlgosimObject;
    begin
      res := Pred.Execute(Context, [AObject], False);
      try
        if res is TAlgosimBoolean then
          Result := TAlgosimBoolean(res).Value
        else
          raise EAlgosimObjectException.CreateFmt(SPredicateDidntReturnBool, [res.TypeName]);
      finally
        res.Free;
      end;
    end,
    NewVal,
    Level);
end;

{ FCN_ReplaceEvery }

procedure FCN_ReplaceEvery.SimpleFunction;
var
  NewVal: TAlgosimObject;
  Level: Integer;
begin
  Args
    .MoveObject(Value)
    .Extract(NewVal)
    .ExtractPos(Level, 1)
    .Close;
  Value.Replace(NewVal, Level);
end;

{ FCN_RemoveAll }

procedure FCN_RemoveAll.SimpleFunction;
var
  OldVal: TAlgosimObject;
  Level: Integer;
begin
  Args
    .MoveObject(Value)
    .Extract(OldVal)
    .ExtractPos(Level, 1)
    .Close;
  Value.RemoveAll(OldVal, Level);
end;

{ FCN_RemoveIf }

procedure FCN_RemoveIf.SimpleFunction;
var
  Pred: TAlgosimFunctionObject;
  Level: Integer;
  &Set: TAlgosimSet;
  i: Integer;
  res: TAlgosimObject;
begin

  if Args.PeekAt(0) is TAlgosimSet then
  begin

    // sets don't support the Remove method

    Args.Extract(&Set).Extract(Pred).Close;
    Result := TAlgosimSet.Create;
    Result.Capacity := &Set.Capacity;

    for i := 1 to &Set.ElementCount do
    begin

      res := Pred.Execute(Context, [&Set.Elements[i]], False);
      try
        if res is TAlgosimBoolean then
        begin
          if not res.ToBoolean then
            Result.AddElement(&Set.Elements[i].Clone);
        end
        else
          raise EAlgosimObjectException.CreateFmt(SPredicateDidntReturnBool, [res.TypeName]);
      finally
        res.Free;
      end;

    end;

    Exit;

  end;

  Args
    .MoveObject(Value)
    .Extract(Pred)
    .ExtractPos(Level, 1)
    .Close;
  Value.RemoveIf(
    function(AObject: TAlgosimObject): Boolean
    var
      res: TAlgosimObject;
    begin
      res := Pred.Execute(Context, [AObject], False);
      try
        if res is TAlgosimBoolean then
          Result := TAlgosimBoolean(res).Value
        else
          raise EAlgosimObjectException.CreateFmt(SPredicateDidntReturnBool, [res.TypeName]);
      finally
        res.Free;
      end;
    end,
    Level);

end;

{ FCN_RealNumber }

procedure FCN_RealNumber.SimpleFunction;
var
  Arg: TAlgosimObject;
begin
  Args.Extract(Arg).Close;
  Result := ASO(Arg.ToRealNumber);
end;

{ FCN_ComplexNumber }

procedure FCN_ComplexNumber.SimpleFunction;
var
  Arg: TAlgosimObject;
begin
  Args.Extract(Arg).Close;
  Result := ASO(Arg.ToComplexNumber);
end;

{ FCN_Number }

procedure FCN_Number.SimpleFunction;
var
  Arg: TAlgosimObject;
begin
  Args.Extract(Arg).Close;
  Result := Arg.ToNumber;
end;

{ FCN_Integer }

procedure FCN_Integer.SimpleFunction;
var
  Arg: TAlgosimObject;
begin
  Args.Extract(Arg).Close;
  Result := ASOInt(Arg.ToASI);
end;

{ FCN_String }

procedure FCN_String.SimpleFunction;
var
  Arg: TAlgosimObject;
begin
  Args.Extract(Arg).Close;
  Result := ASO(Arg.ToString);
end;

{ FCN_RealVector }

procedure FCN_RealVector.SimpleFunction;
var
  Arg: TAlgosimObject;
begin
  Args.Extract(Arg).Close;
  Result := ASO(Arg.AsRealVector);
end;

{ FCN_ComplexVector }

procedure FCN_ComplexVector.SimpleFunction;
var
  Arg: TAlgosimObject;
begin
  Args.Extract(Arg).Close;
  Result := ASO(Arg.AsComplexVector);
end;

{ FCN_Vector }

procedure FCN_Vector.SimpleFunction;
var
  Arg: TAlgosimObject;
begin

  // Create a matrix
  if Args.PeekAt(0) is TAlgosimVector then
  begin

    if HasComplexArg then
      Result := ASO(TComplexMatrix.CreateFromRows(Args.ExtractComplexVectors))
    else
      Result := ASO(TRealMatrix.CreateFromRows(Args.ExtractRealVectors));

    Exit;

  end;

  // Create a vector
  case ChildCount of
    0:
      raise EAlgosimObjectException.Create(SVectDim);
    1:
      begin
        Args.Extract(Arg).Close;
        Result := Arg.AsVector;
      end;
  else
    if HasComplexArg then
      Result := ASO(TComplexVector.Create(Args.ExtractComplexNumbers))
    else
      Result := ASO(TRealVector.Create(Args.ExtractRealNumbers))
  end;

end;

{ FCN_RealMatrix }

procedure FCN_RealMatrix.SimpleFunction;
var
  Arg: TAlgosimObject;
begin
  Args.Extract(Arg).Close;
  Result := ASO(Arg.AsRealMatrix);
end;

{ FCN_ComplexMatrix }

procedure FCN_ComplexMatrix.SimpleFunction;
var
  Arg: TAlgosimObject;
begin
  Args.Extract(Arg).Close;
  Result := ASO(Arg.AsComplexMatrix);
end;

{ FCN_Matrix }

procedure FCN_Matrix.SimpleFunction;
var
  Arg: TAlgosimObject;
  ColCount: Integer;
  rnums: TArray<TASR>;
  cnums: TArray<TASC>;
begin

  case Args.Count of
    0:
      raise EAlgosimObjectException.Create(SMatDim);
    1:
      begin
        Args.Extract(Arg).Close;
        Result := Arg.AsMatrix;
      end;
  else

    if HasComplexArg then
    begin
      cnums := Args.ExtractPos(ColCount).ExtractComplexNumbers;
      Result := ASO(TComplexMatrix.Create(cnums, ColCount));
    end
    else
    begin
      rnums := Args.ExtractPos(ColCount).ExtractRealNumbers;
      Result := ASO(TRealMatrix.Create(rnums, ColCount));
    end;

  end;

end;

{ FCN_Boolean }

procedure FCN_Boolean.SimpleFunction;
var
  Arg: TAlgosimObject;
begin
  Args.Extract(Arg).Close;
  Result := ASO(Arg.ToBoolean);
end;

{ FCN_ToList }

procedure FCN_ToList.SimpleFunction;
var
  Arg: TAlgosimObject;
begin
  Args.Extract(Arg).Close;
  Result := Arg.ToList;
end;

{ FCN_ToSet }

procedure FCN_ToSet.SimpleFunction;
var
  Arg: TAlgosimObject;
begin
  Args.Extract(Arg).Close;
  Result := Arg.ToSet;
end;

{ FCN_ToTable }

procedure FCN_ToTable.SimpleFunction;
var
  Arg: TAlgosimObject;
begin
  Args.Extract(Arg).Close;
  Result := ASO(Arg.ToTable);
end;

{ FCN_BinaryData }

procedure FCN_BinaryData.SimpleFunction;
var
  Arg: TAlgosimObject;
begin
  Args.Extract(Arg).Close;
  Result := Arg.ToBinaryObject;
end;

{ FCN_MatrixFromCols }

procedure FCN_MatrixFromCols.SimpleFunction;
begin

  if HasComplexArg then
    Result := ASO(TComplexMatrix.CreateFromColumns(Args.ExtractComplexVectors))
  else
    Result := ASO(TRealMatrix.CreateFromColumns(Args.ExtractRealVectors));

end;

{ FCN_MatrixFromRows }

procedure FCN_MatrixFromRows.SimpleFunction;
begin

  if HasComplexArg then
    Result := ASO(TComplexMatrix.CreateFromRows(Args.ExtractComplexVectors))
  else
    Result := ASO(TRealMatrix.CreateFromRows(Args.ExtractRealVectors));

end;

{ FCN_MatrixFromBlocks }

procedure FCN_MatrixFromBlocks.SimpleFunction;
var
  ColCount: Integer;
begin

  Args.ExtractPos(ColCount);

  if HasComplexArg then
    Result := ASO(TComplexMatrix.Create(Args.Skip.ExtractComplexMatrices, ColCount))
  else
    Result := ASO(TRealMatrix.Create(Args.Skip.ExtractRealMatrices, ColCount));

end;

{ FCN_List }

procedure FCN_List.SimpleFunction;
var
  i: Integer;
  tmpobj: TAlgosimObject;
begin

  Result := TAlgosimArray.Create;
  Result.Capacity := ChildCount;
  for i := 0 to ChildCount - 1 do
  begin
    TMover<TAlgosimObject>.Move(tmpobj, Children[i].Value);
    Result.AddElement(tmpobj);
  end;

end;

{ FCN_Set }

procedure FCN_Set.SimpleFunction;
var
  i: Integer;
  tmpobj: TAlgosimObject;
begin

  Result := TAlgosimSet.Create;
  Result.Capacity := ChildCount;
  for i := 0 to ChildCount - 1 do
  begin
    TMover<TAlgosimObject>.Move(tmpobj, Children[i].Value); {noexcept}
    Result.AddElement(tmpobj);
  end;

end;

{ FCN_Union }

procedure FCN_Union.SimpleFunction;
var
  U, V: TAlgosimSet;
begin
  Args.Extract(U).Extract(V).Close;
  Result := TAlgosimSet.Union(U, V);
end;

{ FCN_Intersection }

procedure FCN_Intersection.SimpleFunction;
var
  U, V: TAlgosimSet;
begin
  Args.Extract(U).Extract(V).Close;
  Result := TAlgosimSet.Intersection(U, V);
end;

{ FCN_SetDifference }

procedure FCN_SetDifference.SimpleFunction;
var
  U, V: TAlgosimSet;
begin
  Args.Extract(U).Extract(V).Close;
  Result := TAlgosimSet.Difference(U, V);
end;

{ FCN_SymDiff }

procedure FCN_SymDiff.SimpleFunction;
var
  U, V: TAlgosimSet;
begin
  Args.Extract(U).Extract(V).Close;
  Result := TAlgosimSet.SymmetricDifference(U, V);
end;

{ FCN_Complement }

procedure FCN_Complement.SimpleFunction;
var
  Universe: TAlgosimObject;
  U: TAlgosimSet;
begin
  Args.Extract(U).Close;
  Context.GetObjRef('universe', Universe);
  if not (Universe is TAlgosimSet) then
    raise EAlgosimObjectException.CreateFmt(SUniverseNotASet, [Universe.ClassTypeName]);
  Result := TAlgosimSet.Difference(TAlgosimSet(Universe), U);
end;

{ FCN_ElementOf }

procedure FCN_ElementOf.SimpleFunction;
var
  x: TAlgosimObject;
  U: TAlgosimSet;
begin
  Args.Extract(x).Extract(U).Close;
  Result := ASO(TAlgosimSet.ElementOf(x, U));
end;

{ FCN_NotElementOf }

procedure FCN_NotElementOf.SimpleFunction;
var
  x: TAlgosimObject;
  U: TAlgosimSet;
begin
  Args.Extract(x).Extract(U).Close;
  Result := ASO(not TAlgosimSet.ElementOf(x, U));
end;

{ FCN_ContainsAsElement }

procedure FCN_ContainsAsElement.SimpleFunction;
var
  x: TAlgosimObject;
  U: TAlgosimSet;
begin
  Args.Extract(U).Extract(x).Close;
  Result := ASO(TAlgosimSet.ElementOf(x, U));
end;

{ FCN_NotContainsAsElement }

procedure FCN_NotContainsAsElement.SimpleFunction;
var
  x: TAlgosimObject;
  U: TAlgosimSet;
begin
  Args.Extract(U).Extract(x).Close;
  Result := ASO(not TAlgosimSet.ElementOf(x, U));
end;

{ FCN_Subset }

procedure FCN_Subset.SimpleFunction;
var
  U, V: TAlgosimSet;
begin
  Args.Extract(U).Extract(V).Close;
  Result := ASO(TAlgosimSet.Subset(U, V));
end;

{ FCN_ProperSubset }

procedure FCN_ProperSubset.SimpleFunction;
var
  U, V: TAlgosimSet;
begin
  Args.Extract(U).Extract(V).Close;
  Result := ASO(TAlgosimSet.ProperSubset(U, V));
end;

{ FCN_Superset }

procedure FCN_Superset.SimpleFunction;
var
  U, V: TAlgosimSet;
begin
  Args.Extract(U).Extract(V).Close;
  Result := ASO(TAlgosimSet.Subset(V, U));
end;

{ FCN_ProperSuperset }

procedure FCN_ProperSuperset.SimpleFunction;
var
  U, V: TAlgosimSet;
begin
  Args.Extract(U).Extract(V).Close;
  Result := ASO(TAlgosimSet.ProperSubset(V, U));
end;

{ FCN_TypeName }

procedure FCN_TypeName.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASO(Arg.TypeName);
end;

{ FCN_ClassTypeData }

procedure FCN_ClassTypeData.DoExecute;

{$IF SizeOf(TAlgosimObjectClassFlags) = 1}
type TClassFlagInt = UInt8;
{$ELSEIF SizeOf(TAlgosimObjectClassFlags) = 2}
type TClassFlagInt = UInt16;
{$ELSEIF SizeOf(TAlgosimObjectClassFlags) = 4}
type TClassFlagInt = UInt32;
{$ENDIF}

var
  Arg: TAlgosimObject;
begin

  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;

  with Arg.ClassData do
    Result := ASO(
      [
        sm('name', ASO(ClassTypeName)),
        sm('ClassFlags',
          ASOInt(
              {$IF Declared(TClassFlagInt)}
                TClassFlagInt(ClassFlags)
              {$ELSE}
                -1
              {$ENDIF}
            )
          ),
        sm('IsObjectContainer', ASO(asoObjectContainer in ClassFlags)),
        sm('IsValueContainer', ASO(asoValueContainer in ClassFlags)),
        sm('IsPlanarContainer', ASO(asoPlanarContainer in ClassFlags)),
        sm('IsOrderedContainer', ASO(asoOrderedContainer in ClassFlags)),
        sm('IsComplexType', ASO(asoComplex in ClassFlags))
      ]
    );

end;

{ FCN_ClassTypeName }

procedure FCN_ClassTypeName.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASO(Arg.ClassTypeName);
end;

{ FCN_HasComplexType }

procedure FCN_HasComplexType.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASO(Arg.IsComplex);
end;

{ FCN_IsObjectContainer }

procedure FCN_IsObjectContainer.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASO(Arg.IsObjectContainer);
end;

{ FCN_IsValueContainer }

procedure FCN_IsValueContainer.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASO(Arg.IsValueContainer);
end;

{ FCN_IsPlanarContainer }

procedure FCN_IsPlanarContainer.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASO(Arg.IsPlanarContainer);
end;

{ FCN_IsOrderedContainer }

procedure FCN_IsOrderedContainer.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASO(Arg.IsOrderedContainer);
end;

{ FCN_Beep }

procedure FCN_Beep.SimpleFunction;
resourcestring
  SWin32MessageBeep = 'Couldn''t produce message beep using the native OS API.';
  SWin32Beep = 'Couldn''t produce sinusoidal beep using the native OS API.';
  SBeepSoundType = 'Unsupported beep sound type: "%s"';
  SToneFrequency = 'Unsupported tone frequency: %d Hz';
  SToneDuration = 'Too long tone duration: %d ms';
var
  s: string;
  MB_const: Integer;
  res: Boolean;
  freq, dur: Integer;
begin

  CheckNumArgs([0, 1, 2]);

  case ChildCount of
    0..1:
      begin

        Args.Extract(s, 'default').Close;

        if SameText(s, 'default') then
          MB_const := MB_OK
        else if SameText(s, 'information') then
          MB_const := MB_ICONINFORMATION
        else if SameText(s, 'warning') then
          MB_const := MB_ICONWARNING
        else if SameText(s, 'error') then
          MB_const := MB_ICONERROR
        else if SameText(s, 'question') then
          MB_const := MB_ICONQUESTION
        else
          raise EInvArgs.CreateFmt(SBeepSoundType, [s]);

        res := Windows.MessageBeep(MB_const);

        if not res then
          raise EAlgosimOSError.Create(SWin32MessageBeep);

      end;

    2:
      begin

        Args.ExtractPos(freq).ExtractNonNeg(dur).Close;

        if not InRange(freq, 37, 32767) then
          raise EInvArgs.CreateFmt(SToneFrequency, [freq]);

        if dur > 30000 then
          raise EInvArgs.CreateFmt(SToneDuration, [dur]);

        res := Windows.Beep(freq, dur);

        if not res then
          raise EAlgosimOSError.Create(SWin32Beep);

      end;
  else
    ErrInvalidArguments;
  end;

  Result := ASO(null);

end;

{ FCN_Wait }

procedure FCN_Wait.SimpleFunction;
var
  Dur: TASR;
  C0, C1: UInt64;
  DurMS: Cardinal;
  SignaledObj: THandleObject;
begin

  Args.ExtractNonNeg(Dur).Close;

  if Round(1000*Dur) > DurMS.MaxValue then
    raise Exception.Create('Too large timeout.');

  DurMS := Round(1000*Dur);

  if TThread.Current.ThreadID = MainThreadID then
  begin
    Sleep(DurMS);
    Exit;
  end;

  while DurMS > 0 do
  begin
    C0 := GetTickCount64;
    case
      TEvent.WaitForMultiple(
        [Context.AbortCurrentEvent, Context.EnterPauseEvent],
        DurMS,
        False,
        SignaledObj
      )
    of
      wrSignaled:
        begin
          if SignaledObj = Context.AbortCurrentEvent then
            ManualAbort
          else if SignaledObj = Context.EnterPauseEvent then
          begin
            C1 := GetTickCount64;
            if DoPause(Context.ResumeEvent, Context.AbortCurrentEvent) = raAbort then
              ManualAbort;
            if C1 - C0 >= DurMS then
            begin
              Result := ASO(null);
              Exit;
            end
            else
              Dec(DurMS, Cardinal(C1 - C0));
          end;
        end;
      wrTimeout:
        begin
          Result := ASO(null);
          Exit;
        end
    else
      raise Exception.Create('Wait failed.');
    end;
  end;

end;

{ FCN_GetTickCount }

procedure FCN_GetTickCount.SimpleFunction;
begin
  Args.Close;
  Result := ASOInt(GetTickCount64);
end;

{ FCN_Heaviside }

procedure FCN_Heaviside.InitNode;
begin
  rfcn := ASNum.Heaviside;
end;

{ FCN_Ramp }

procedure FCN_Ramp.InitNode;
begin
  rfcn := ASNum.Ramp;
end;

{ FCN_Rect }

procedure FCN_Rect.InitNode;
begin
  rfcn := ASNum.Rectfcn;
end;

{ FCN_Tri }

procedure FCN_Tri.InitNode;
begin
  rfcn := ASNum.Tri;
end;

{ FCN_GetProperty }

procedure FCN_GetProperty.SimpleFunction;
var
  Arg: string;
begin
  Args.Extract(Arg).Close;
  Result := Context.GetPropVal(Arg);
end;

{ FCN_Integrate }

procedure FCN_Integrate.DoExecute;
resourcestring
  SIntegrandRealValued = 'Integrand must be a real-valued function.';
const
  ARG_INDEX_EXPRESSION = 0;
  ARG_INDEX_SYMBOL = 1;
  ARG_INDEX_LOWER_LIMIT = 2;
  ARG_INDEX_UPPER_LIMIT = 3;
var
  symbol: string;
  symbols: TList<TASExprNode>;
  LowerBound, UpperBound: TASR;
  IntegrationParams: TIntegrationParams;
  Δx: TASR;
begin

  CheckNumArgs([4, 5]);
  CheckSymbol(ARG_INDEX_SYMBOL);
  symbol := TASSymbolExprNode(Children[ARG_INDEX_SYMBOL]).Symbol;

  if not EvalChildren(ARG_INDEX_LOWER_LIMIT) then
    Exit;

  Args.Skip.Skip.Extract(LowerBound).Extract(UpperBound).ExtractPos(Δx, 0).Close;

  symbols := TList<TASExprNode>.Create;
  try
    FindSymbols(Children[ARG_INDEX_EXPRESSION], symbol, symbols);

    if Δx > 0 then
      IntegrationParams := TIntegrationParams.Delta(Δx)
    else
      IntegrationParams := TIntegrationParams.N(100000);

    Value := ASO
      (
        ASNum.integrate(
          function(const X: TASR): TASR
          begin
            PopulateSymbols(symbols, ASO(X));
            Children[ARG_INDEX_EXPRESSION].Evaluate;
            CheckFailure(Children[ARG_INDEX_EXPRESSION].Value);
            if not Children[ARG_INDEX_EXPRESSION].Value.TryToASR(Result) then
              raise EAlgosimObjectException.Create(SIntegrandRealValued);
          end,
          LowerBound,
          UpperBound,
          IntegrationParams
        )
      );

  finally
    symbols.Free;
  end;

end;

{ FCN_Differentiate }

procedure FCN_Differentiate.DoExecute;
const
  ARG_INDEX_EXPRESSION = 0;
  ARG_INDEX_SYMBOL = 1;
  ARG_INDEX_POINT = 2;
  ARG_INDEX_EPSILON = 3;
var
  symbol: string;
  symbols: TList<TASExprNode>;
  Point: TASR;
  Epsilon: TASR;
begin

  CheckNumArgs([3, 4]);
  CheckSymbol(ARG_INDEX_SYMBOL);
  symbol := TASSymbolExprNode(Children[ARG_INDEX_SYMBOL]).Symbol;

  if not EvalChildren(2) then Exit;
  Args.Skip.Skip.Extract(Point).ExtractNonNeg(Epsilon, 1E-6).Close;

  var a := TAlgosimObject(nil);
  var b := TAlgosimObject(nil);
  symbols := TList<TASExprNode>.Create;
  try

    FindSymbols(Children[ARG_INDEX_EXPRESSION], symbol, symbols);

    PopulateSymbols(symbols, ASO(Point + Epsilon));
    Children[ARG_INDEX_EXPRESSION].Evaluate;
    CheckFailure(Children[ARG_INDEX_EXPRESSION].Value);

    b := Children[ARG_INDEX_EXPRESSION].Value.Clone;

    PopulateSymbols(symbols, ASO(Point - Epsilon));
    Children[ARG_INDEX_EXPRESSION].Evaluate;
    CheckFailure(Children[ARG_INDEX_EXPRESSION].Value);

    a := Children[ARG_INDEX_EXPRESSION].Value.Clone;

    var DiffQuotient := TASExpression.Create(FCN_Divide);
    try
      DiffQuotient.Context := Self.Context;
      var LDifference := DiffQuotient.Root.AddChild(FCN_Subtract);
      DiffQuotient.Root.AddChild(ASO(2*Epsilon));
      LDifference.AddChild(b); b := niL;
      LDifference.AddChild(a); a := nil;
      DiffQuotient.Evaluate;
      CheckFailure(DiffQuotient.Root.Value);
      TMover<TAlgosimObject>.Move(Value, DiffQuotient.Root.Value);
    finally
      DiffQuotient.Free;
    end;

  finally
    symbols.Free;
    a.Free;
    b.Free;
  end;

end;

{ FCN_Length }

procedure FCN_Length.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASOInt(Arg.ValueCount);
end;

{ FCN_Pos }

procedure FCN_Pos.SimpleFunction;
var
  Str, Substr: string;
  Flags: TSysCharSet;
  SearchOptions: TStringSearchOptions;
  Offset: Integer;
begin

  Args
    .Extract(Str)
    .Extract(Substr)
    .Extract(Flags, restr, ['i', 'w'], defval, [])
    .ExtractPos(Offset, 1)
    .Close;

  SearchOptions := [];
  if AnsiChar('i') in Flags then
    Include(SearchOptions, ssoIgnoreCase);
  if AnsiChar('w') in Flags then
    Include(SearchOptions, ssoWholeWords);

  Dec(Offset);

  Result := ASOInt(ASStrFcns.SubstringFirstIndex(Substr, Str, SearchOptions, Offset));

end;

{ FCN_StringContains }

procedure FCN_StringContains.SimpleFunction;
var
  Str, Substr: string;
  Flags: TSysCharSet;
  SearchOptions: TStringSearchOptions;
  Offset: Integer;
begin

  Args
    .Extract(Str)
    .Extract(Substr)
    .Extract(Flags, restr, ['i', 'w'], defval, [])
    .ExtractPos(Offset, 1)
    .Close;

  SearchOptions := [];
  if AnsiChar('i') in Flags then
    Include(SearchOptions, ssoIgnoreCase);
  if AnsiChar('w') in Flags then
    Include(SearchOptions, ssoWholeWords);

  Dec(Offset);

  Result := ASO(ASStrFcns.SubstringFirstIndex(Substr, Str, SearchOptions, Offset) <> 0);

end;

{ FCN_SubstringCount }

procedure FCN_SubstringCount.SimpleFunction;
var
  Str, Substr: string;
  Flags: TSysCharSet;
  SearchOptions: TStringSearchOptions;
  Offset: Integer;
begin

  Args
    .Extract(Str)
    .Extract(Substr)
    .Extract(Flags, restr, ['i', 'w'], defval, [])
    .ExtractPos(Offset, 1)
    .Close;

  SearchOptions := [];
  if AnsiChar('i') in Flags then
    Include(SearchOptions, ssoIgnoreCase);
  if AnsiChar('w') in Flags then
    Include(SearchOptions, ssoWholeWords);

  Dec(Offset);

  Result := ASOInt(ASStrFcns.SubstringCount(Substr, Str, SearchOptions, Offset));

end;

{ FCN_SubstringIndices }

procedure FCN_SubstringIndices.SimpleFunction;
var
  Str, Substr: string;
  Flags: TSysCharSet;
  SearchOptions: TStringSearchOptions;
  Offset: Integer;
  List: TList<Integer>;
begin

  Args
    .Extract(Str)
    .Extract(Substr)
    .Extract(Flags, restr, ['i', 'w'], defval, [])
    .ExtractPos(Offset, 1)
    .Close;

  SearchOptions := [];
  if AnsiChar('i') in Flags then
    Include(SearchOptions, ssoIgnoreCase);
  if AnsiChar('w') in Flags then
    Include(SearchOptions, ssoWholeWords);

  Dec(Offset);

  List := TList<Integer>.Create;
  try
    ASStrFcns.SubstringCount(Substr, Str, SearchOptions, Offset, List);
    Result := TAlgosimArray.CreateWithValue(List.ToArray);
  finally
    List.Free;
  end;

end;

{ FCN_StringReplace }

procedure FCN_StringReplace.SimpleFunction;
var
  Str, Substr, NewText: string;
  Flags: TSysCharSet;
  SearchOptions: TStringSearchOptions;
  Offset: Integer;
begin

  Args
    .Extract(Str)
    .Extract(Substr)
    .Extract(NewText)
    .Extract(Flags, restr, ['i', 'w'], defval, [])
    .ExtractPos(Offset, 1)
    .Close;

  SearchOptions := [];
  if AnsiChar('i') in Flags then
    Include(SearchOptions, ssoIgnoreCase);
  if AnsiChar('w') in Flags then
    Include(SearchOptions, ssoWholeWords);

  Dec(Offset);

  Result := ASO(ASStrFcns.StringReplace(Str, Substr, NewText, SearchOptions, Offset));

end;

{ FCN_Split }

procedure FCN_Split.SimpleFunction;
var
  Str, Sep: string;
  Seps: TArray<string>;
begin
  if Args.PeekAt(1) is TAlgosimString then
  begin
    Args.Extract(Str).Extract(Sep).Close;
    Result := TAlgosimArray.CreateWithValue(Str.Split([Sep]));
  end
  else
  begin
    Args.Extract(Str).Extract(Seps).Close;
    Result := TAlgosimArray.CreateWithValue(Str.Split(Seps));
  end;
end;

{ FCN_Join }

procedure FCN_Join.SimpleFunction;
var
  List, Elem: TAlgosimObject;
  Fcn: TAlgosimFunctionObject;
  Sep, Li, Ri, Lo, Ro: string;
  strs: TArray<string>;
  res: string;
  i, c, j: Integer;
begin

  Fcn := nil;

  if Args.PeekAt(1) is TAlgosimFunctionObject then
    Args
      .Extract(List)
      .Extract(Fcn)
      .Extract(Sep, ', ')
      .Extract(Li, '')
      .Extract(Ri, '')
      .Extract(Lo, '')
      .Extract(Ro, '')
      .Close
  else
    Args
      .Extract(List)
      .Extract(Sep, ', ')
      .Extract(Li, '')
      .Extract(Ri, '')
      .Extract(Lo, '')
      .Extract(Ro, '')
      .Close;

  if not List.IsObjectContainer then
    ErrInvalidArguments;

  SetLength(strs, List.ValueCount);
  c := 0;
  for i := 0 to High(strs) do
  begin
    if Assigned(Fcn) then
    begin
      Elem := Fcn.Execute(Context, [List.Elements[i + 1]], False);
      try
        strs[i] := Elem.ToString;
      finally
        Elem.Free;
      end;
    end
    else
      strs[i] := List.Elements[i + 1].ToString;
    Inc(c, strs[i].Length);
  end;

  SetLength(res,
    Lo.Length + Ro.Length +
    c +
    List.ElementCount * (Li.Length + Ri.Length) +
    Math.Max(0, List.ElementCount - 1) * Sep.Length);

  j := 1;

  if not Lo.IsEmpty then
  begin
    Move(Lo[1], res[j], Lo.Length * sizeof(char));
    Inc(j, Lo.Length);
  end;

  for i := 0 to High(strs) do
  begin
    if (i > 0) and not Sep.IsEmpty then
    begin
      Move(Sep[1], res[j], Sep.Length * sizeof(char));
      Inc(j, Sep.Length);
    end;
    if not Li.IsEmpty then
    begin
      Move(Li[1], res[j], Li.Length * sizeof(char));
      Inc(j, Li.Length);
    end;
    if not strs[i].IsEmpty then
    begin
      Move(strs[i][1], res[j], strs[i].Length * sizeof(char));
      Inc(j, strs[i].Length);
    end;
    if not Ri.IsEmpty then
    begin
      Move(Ri[1], res[j], Ri.Length * sizeof(char));
      Inc(j, Ri.Length);
    end;
  end;

  if not Ro.IsEmpty then
    Move(Ro[1], res[j], Ro.Length * sizeof(char));

  Result := ASO(res);

end;

{ FCN_UpperCase }

procedure FCN_UpperCase.SimpleFunction;
var
  Arg: string;
begin
  Args.Extract(Arg).Close;
  Result := ASO(AnsiUpperCase(Arg));
end;

{ FCN_LowerCase }

procedure FCN_LowerCase.SimpleFunction;
var
  Arg: string;
begin
  Args.Extract(Arg).Close;
  Result := ASO(AnsiLowerCase(Arg));
end;

{ FCN_InvertCase }

procedure FCN_InvertCase.SimpleFunction;
var
  Arg: string;
begin
  Args.Extract(Arg).Close;
  Result := ASO(TextTransformFunc(ChrInvertCase)(Arg));
end;

{ FCN_TitleCase }

procedure FCN_TitleCase.SimpleFunction;
var
  Arg: string;
begin
  Args.Extract(Arg).Close;
  Result := ASO(TxtTitleCase(Arg));
end;

{ FCN_SentenceCase }

procedure FCN_SentenceCase.SimpleFunction;
var
  Arg: string;
begin
  Args.Extract(Arg).Close;
  Result := ASO(TxtSentenceCase(Arg));
end;

{ FCN_ROT13 }

procedure FCN_ROT13.SimpleFunction;
var
  Arg: string;
begin
  Args.Extract(Arg).Close;
  Result := ASO(TextTransformFunc(ChrROT13)(Arg));
end;

{ FCN_Caesar }

procedure FCN_Caesar.SimpleFunction;
var
  str: string;
  N: Integer;
begin
  Args.Extract(str).Extract(N).Close;
  Result := ASO(TextTransformFunc(ChrCaesar(N))(str));
end;

{ FCN_Vigenère }

procedure FCN_Vigenère.SimpleFunction;
var
  str, psw: string;
begin
  Args.Extract(str).Extract(psw).Close;
  Result := ASO(TxtVigenère(UpperCase(psw))(str));
end;

{ FCN_VigenèreDecode }

procedure FCN_VigenèreDecode.SimpleFunction;
var
  str, psw: string;
begin
  Args.Extract(str).Extract(psw).Close;
  Result := ASO(TxtVigenère(UpperCase(psw), True)(str));
end;

{ FCN_Trim }

procedure FCN_Trim.SimpleFunction;
var
  Arg: string;
begin
  Args.Extract(Arg).Close;
  Result := ASO(Arg.Trim);
end;

{ FCN_TrimLeft }

procedure FCN_TrimLeft.SimpleFunction;
var
  Arg: string;
begin
  Args.Extract(Arg).Close;
  Result := ASO(Arg.TrimLeft);
end;

{ FCN_TrimRight }

procedure FCN_TrimRight.SimpleFunction;
var
  Arg: string;
begin
  Args.Extract(Arg).Close;
  Result := ASO(Arg.TrimRight);
end;

{ FCN_Pad }

procedure FCN_Pad.SimpleFunction;
var
  S: string;
  N: Integer;
  Ac: Char;
  A: TAlignment;
  C: Char;
begin
  Args.Extract(S).ExtractNonNeg(N).Extract(Ac, ['l', 'r', 'c'], 'l').Extract(C, #32).Close;
  case Ac of
    'l':
      A := taLeftJustify;
    'r':
      A := taRightJustify;
    'c':
      A := taCenter;
  else
    A := taLeftJustify;
  end;
  Result := ASO(Pad(S, N, A, C));
end;

{ FCN_Format }

procedure FCN_Format.SimpleFunction;
resourcestring
  SInvalidFormatString = 'Invalid format string.';
  SFormatStringRef = 'Format string references non-existing object.';
var
  FmtStr: string;
  Vals: TAlgosimArray;
  counts: array[0..9] of Integer; // 0 is the %% count; 1..9 are the counts of the actual object references
  strs: array[1..9] of string;
  i, j, digit: Integer;
  len: Integer;
  res: string;
  maxindex: Integer;
begin

  Args.Extract(FmtStr).Extract(Vals).Close;

  FillChar(counts, sizeof(counts), 0);
  i := 1;
  while i <= FmtStr.Length do
    if FmtStr[i] = '%' then
      if i = FmtStr.Length then
        raise EInvArgs.Create(SInvalidFormatString)
      else if FmtStr[i + 1] = '%' then
      begin
        Inc(counts[0]);
        Inc(i, 2);
      end
      else if InRange(Ord(FmtStr[i + 1]), Ord('1'), Ord('9')) then
      begin
        digit := Ord(FmtStr[i + 1]) - Ord('0');
        Inc(counts[digit]);
        Inc(i, 2);
      end
      else
        raise EInvArgs.Create(SInvalidFormatString)
    else
      Inc(i);

  maxindex := -1;
  for i := High(counts) downto 0 do
    if counts[i] > 0 then
    begin
      maxindex := i;
      Break;
    end;

  if maxindex = -1 then
  begin
    Result := ASO(FmtStr);
    Exit;
  end;

  if maxindex > Vals.ElementCount then
    raise EInvArgs.Create(SFormatStringRef);

  for i := 1 to High(strs) do
    if counts[i] > 0 then
      strs[i] := Vals.Elements[i].GetAsSingleLineText(Context.FormatOptions);

  len := FmtStr.Length;
  Dec(len, counts[0]);
  for i := 1 to High(counts) do
    Inc(len, counts[i] * (strs[i].Length - 2));

  SetLength(res, len);

  i := 1;
  j := 1;
  while i <= FmtStr.Length do
    if FmtStr[i] = '%' then
    begin
      Assert(i < FmtStr.Length);
      if FmtStr[i + 1] = '%' then
      begin
        res[j] := '%';
        Inc(j);
      end
      else
      begin
        digit := Ord(FmtStr[i + 1]) - Ord('0');
        Assert(InRange(digit, 1, 9));
        if not strs[digit].IsEmpty then
          Move(strs[digit][1], res[j], strs[digit].Length * sizeof(char));
        Inc(j, strs[digit].Length);
      end;
      Inc(i, 2);
    end
    else
    begin
      res[j] := FmtStr[i];
      Inc(j);
      Inc(i);
    end;

  Assert(i = FmtStr.Length + 1);
  Assert(j = res.Length + 1);

  Result := ASO(res);

end;

{ FCN_IndexOf }

procedure FCN_IndexOf.DoExecute;
var
  Container, Member: TAlgosimObject;
  Eps: TASR;
begin
  CheckNumArgs([2, 3]);
  if not ExtractRef(0, Container) then Exit;
  if not ExtractRef(1, Member) then Exit;
  case Args.Count of
    2:
      Result := Container.IndexOfValue(Member);
    3:
      begin
        if not EvalChild(2) then Exit;
        Args(2).ExtractNonNeg(Eps);
        Result := Container.IndexOfValueEps(Member, Eps);
      end;
  else
    ErrInvalidArguments;
  end;
end;

{ TCharTestFunction }

procedure TCharTestFunction.SimpleFunction;
var
  Arg: Char;
begin
  Args.Extract(Arg).Close;
  Result := ASO(fcn(Arg));
end;

{$WARN SYMBOL_DEPRECATED OFF}

{ FCN_ChrIsLetter }

procedure FCN_ChrIsLetter.InitNode;
begin
  fcn := TCharacter.IsLetter;
end;

{ FCN_ChrIsDigit }

procedure FCN_ChrIsDigit.InitNode;
begin
  fcn := TCharacter.IsDigit;
end;

{ FCN_ChrIsLetterOrDigit }

procedure FCN_ChrIsLetterOrDigit.InitNode;
begin
  fcn := TCharacter.IsLetterOrDigit;
end;

{ FCN_ChrIsNumber }

procedure FCN_ChrIsNumber.InitNode;
begin
  fcn := TCharacter.IsNumber;
end;

{ FCN_ChrIsPunctuation }

procedure FCN_ChrIsPunctuation.InitNode;
begin
  fcn := TCharacter.IsPunctuation;
end;

{ FCN_ChrIsSeparator }

procedure FCN_ChrIsSeparator.InitNode;
begin
  fcn := TCharacter.IsSeparator;
end;

{ FCN_ChrIsWhitespace }

procedure FCN_ChrIsWhitespace.InitNode;
begin
  fcn := TCharacter.IsWhitespace;
end;

{ FCN_ChrIsUpperCase }

procedure FCN_ChrIsUpperCase.InitNode;
begin
  fcn := TCharacter.IsUpper;
end;

{ FCN_ChrIsLowerCase }

procedure FCN_ChrIsLowerCase.InitNode;
begin
  fcn := TCharacter.IsLower;
end;

{ FCN_ChrIsSymbol }

procedure FCN_ChrIsSymbol.InitNode;
begin
  fcn := TCharacter.IsSymbol;
end;

{ FCN_ChrIsASCII }

procedure FCN_ChrIsASCII.InitNode;
begin
  fcn := IsASCII;
end;

class function FCN_ChrIsASCII.IsASCII(C: char): Boolean;
begin
  Result := Ord(C) <= 127;
end;

{ FCN_ChrIsControl }

procedure FCN_ChrIsControl.InitNode;
begin
  fcn := TCharacter.IsControl;
end;

{$WARN SYMBOL_DEPRECATED DEFAULT}

{ FCN_ChrName }

procedure FCN_ChrName.SimpleFunction;
var
  Chr: Char;
begin
  Args.Extract(Chr).Close;
  Result := ASO(UCD.GetChrName(Chr));
end;

{ FCN_ChrBlock }

procedure FCN_ChrBlock.SimpleFunction;
var
  Chr: Char;
begin
  Args.Extract(Chr).Close;
  Result := ASO(UCD.GetChrBlock(Chr));
end;

{ FCN_ListChrBlocks }

procedure FCN_ListChrBlocks.SimpleFunction;
var
  i: Integer;
begin
  Args.Close;
  Result := TAlgosimArray.Create;
  Result.Capacity := UCD.BlockCount;
  for i := 0 to UCD.BlockCount - 1 do
    Result.AddElement(ASO(UCD.Blocks[i].BlockName));
end;

{ FCN_ChrBlockRange }

procedure FCN_ChrBlockRange.SimpleFunction;
resourcestring
  SNoUnicodeBlock = 'There is no Unicode block named "%s".';
var
  Arg: string;
  i: Integer;
begin
  Args.Extract(Arg).Close;
  for i := 0 to UCD.BlockCount - 1 do
    if SameText(UCD.Blocks[i].BlockName, Arg) then
    begin
      Result := TAlgosimStructure.CreateWithValue(
        [
          sm('start', ASOInt(UCD.Blocks[i].BlockBegin)),
          sm('end', ASOInt(UCD.Blocks[i].BlockEnd))
        ]
      );
      Exit;
    end;
  raise EInvArgs.CreateFmt(SNoUnicodeBlock, [Arg]);
end;

{ FCN_Character }

procedure FCN_Character.SimpleFunction;
var
  x: Integer;
begin
  Args.ExtractNonNeg(x).Close;
  Result := ASO(Char(x));
end;

{ FCN_ChrCode }

procedure FCN_ChrCode.SimpleFunction;
var
  c: Char;
begin
  Args.Extract(c).Close;
  Result := ASOInt(Ord(c), 16);
end;

{ FCN_ChrNumVal }

procedure FCN_ChrNumVal.SimpleFunction;
var
  c: Char;
  val: Double;
begin
  Args.Extract(c).Close;
  val := c.GetNumericValue;
  if IsInteger(val) then
    Result := ASOInt(Round(val))
  else
    Result := ASO(val);
end;

{ FCN_Odd }

procedure FCN_Odd.SimpleFunction;
var
  N: TASI;
begin
  Args.Extract(N).Close;
  Result := ASO(Odd(N));
end;

{ FCN_Even }

procedure FCN_Even.SimpleFunction;
var
  N: TASI;
begin
  Args.Extract(N).Close;
  Result := ASO(not Odd(N));
end;

{ FCN_Date }

procedure FCN_Date.SimpleFunction;
var
  Date: TDate;
  Year, Month, Day: Integer;
begin

  CheckNumArgs([0, 1, 3]);

  case Self.ChildCount of
    0:
      Result := ASODate(GetCurDate);
    1:
      begin
        Args.Extract(Date).Close;
        Result := ASODate(Date);
      end;
    3:
      begin
        Args.Extract(Year).Extract(Month).Extract(Day).Close;
        Result := ASODate(Year, Month, Day);
      end;
  else
    ErrInvalidArguments;
  end;

end;

{ FCN_Time }

procedure FCN_Time.SimpleFunction;
var
  Time: TTime;
  Hour, Minute, Second, Millisecond: Integer;
begin

  CheckNumArgs([0, 1, 3, 4]);

  case Self.ChildCount of
    0:
      Result := ASOTime(GetCurTime);
    1:
      begin
        Args.Extract(Time).Close;
        Result := ASOTime(Time);
      end;
    3, 4:
      begin
        Args
          .Extract(Hour)
          .Extract(Minute)
          .Extract(Second)
          .Extract(Millisecond, 0)
          .Close;
        Result := ASOTime(Hour, Minute, Second, Millisecond);
      end;
  else
    ErrInvalidArguments;
  end;

end;

{ FCN_Now }

procedure FCN_Now.SimpleFunction;
begin
  Args.Close;
  Result := ASODateTime(GetCurDateTime);
end;

{ FCN_DateTime }

procedure FCN_DateTime.SimpleFunction;
var
  DateTime: TDateTime;
  DateObj, TimeObj: TAlgosimTypedStructure;
  Year, Month, Day,
  Hour, Minute, Second, Millisecond: Integer;
begin

  case Self.ChildCount of
    0:
      Result := ASODateTime(GetCurDateTime);
    1:
      begin
        Args.Extract(DateTime).Close;
        Result := ASODateTime(DateTime);
      end;
    2:
      begin
        Args.MoveObject(DateObj, stDate).MoveObject(TimeObj, stTime).Close;
        Result := stDateTime.New([DateObj, TimeObj]);
      end;
  else
    Args
      .Extract(Year)
      .Extract(Month)
      .Extract(Day)
      .Extract(Hour, 0)
      .Extract(Minute, 0)
      .Extract(Second, 0)
      .Extract(Millisecond, 0)
      .Close;
    Result := ASODateTime(Year, Month, Day, Hour, Minute, Second, Millisecond);
  end;

end;

{ TTimeOneParamFcn }

procedure TTimeOneParamFcn.SimpleFunction;
var
  DateTime: TDateTime;
  Amt64: Int64;
  Amt32: Int32;
begin

  if Assigned(fcn64) then
  begin
    Args.Extract(DateTime).Extract(Amt64).Close;
    DateTime := fcn64(DateTime, Amt64);
  end
  else if Assigned(fcn32) then
  begin
    Args.Extract(DateTime).Extract(Amt32).Close;
    DateTime := fcn32(DateTime, Amt32);
  end
  else
    ErrInternal;

  if Args.PeekAt(0) is TAlgosimNumber then
    Result := ASO(DateTime)
  else
    Result := ASODateTime(DateTime);

end;

{ FCN_AddMilliseconds }

procedure FCN_AddMilliseconds.InitNode;
begin
  fcn64 := IncMillisecond;
end;

{ FCN_AddSeconds }

procedure FCN_AddSeconds.InitNode;
begin
  fcn64 := IncSecond;
end;

{ FCN_AddMinutes }

procedure FCN_AddMinutes.InitNode;
begin
  fcn64 := IncMinute;
end;

{ FCN_AddHours }

procedure FCN_AddHours.InitNode;
begin
  fcn64 := IncHour;
end;

{ FCN_AddDays }

procedure FCN_AddDays.InitNode;
begin
  fcn32 := IncDay;
end;

{ FCN_AddWeeks }

procedure FCN_AddWeeks.InitNode;
begin
  fcn32 := IncWeek;
end;

{ FCN_AddMonths }

function __IncMonth(const ADateTime: TDateTime; const Amount: Integer): TDateTime; inline;
begin
  Result := IncMonth(ADateTime, Amount);
end;

procedure FCN_AddMonths.InitNode;
begin
  fcn32 := __IncMonth;
end;

{ FCN_AddYears }

procedure FCN_AddYears.InitNode;
begin
  fcn32 := IncYear;
end;

function __ValidateDate(const ADate: TAlgosimStructure): Boolean;
var
  Year, Month, Day: Integer;
begin
  Result := ADate.Values['year'].TryToInt32(Year) and
    ADate.Values['month'].TryToInt32(Month) and
    ADate.Values['day'].TryToInt32(Day) and
    InRange(Year, Word.MinValue, Word.MaxValue) and
    InRange(Month, Word.MinValue, Word.MaxValue) and
    InRange(Day, Word.MinValue, Word.MaxValue) and
    IsValidDate(Year, Month, Day);
end;

function __ValidateTime(const ATime: TAlgosimStructure): Boolean;
var
  Hour, Minute, Second, Millisecond: Integer;
begin
  Result := ATime.Values['hour'].TryToInt32(Hour) and
    ATime.Values['minute'].TryToInt32(Minute) and
    ATime.Values['second'].TryToInt32(Second) and
    ATime.Values['millisecond'].TryToInt32(Millisecond) and
    InRange(Hour, Word.MinValue, Word.MaxValue) and
    InRange(Minute, Word.MinValue, Word.MaxValue) and
    InRange(Second, Word.MinValue, Word.MaxValue) and
    InRange(Millisecond, Word.MinValue, Word.MaxValue) and
    IsValidTime(Hour, Minute, Second, Millisecond);
end;

function __ValidateDateTime(const ADateTime: TAlgosimStructure): Boolean;
var
  Date, Time: TAlgosimStructure;
begin
  Date := ADateTime.Values['date'] as TAlgosimStructure;
  Time := ADateTime.Values['time'] as TAlgosimStructure;
  Result := __ValidateDate(Date) and __ValidateTime(Time);
end;

{ FCN_DateValid }

procedure FCN_DateValid.SimpleFunction;
var
  DateObj: TAlgosimTypedStructure;
begin
  Args.Extract(DateObj, stDate).Close;
  Result := ASO(stDate.ValidateAgainst(DateObj) and
    __ValidateDate(TAlgosimStructure(DateObj)));
end;

{ FCN_TimeValid }

procedure FCN_TimeValid.SimpleFunction;
var
  TimeObj: TAlgosimTypedStructure;
begin
  Args.Extract(TimeObj, stTime);
  Result := ASO(stTime.ValidateAgainst(TimeObj) and
    __ValidateTime(TAlgosimStructure(TimeObj)));
end;

{ FCN_DateTimeValid }

procedure FCN_DateTimeValid.SimpleFunction;
var
  DateTimeObj: TAlgosimTypedStructure;
begin
  Args.Extract(DateTimeObj, stDateTime);
  Result := ASO(stDateTime.ValidateAgainst(DateTimeObj) and
    __ValidateDateTime(TAlgosimStructure(DateTimeObj)));
end;

{ TTimeTimeDoubleFcn }

procedure TTimeTimeDoubleFcn.SimpleFunction;
var
  DateTime1, DateTime2: TDateTime;
begin
  Args.Extract(DateTime1).Extract(DateTime2).Close;
  Result := ASO(fcn(DateTime1, DateTime2));
end;

{ FCN_MillisecondsBetween }

procedure FCN_MillisecondsBetween.InitNode;
begin
  fcn := MilliSecondSpan;
end;

{ FCN_SecondsBetween }

procedure FCN_SecondsBetween.InitNode;
begin
  fcn := SecondSpan;
end;

{ FCN_MinutesBetween }

procedure FCN_MinutesBetween.InitNode;
begin
  fcn := MinuteSpan;
end;

{ FCN_HoursBetween }

procedure FCN_HoursBetween.InitNode;
begin
  fcn := HourSpan;
end;

{ FCN_DaysBetween }

procedure FCN_DaysBetween.InitNode;
begin
  fcn := DaySpan;
end;

{ FCN_WeeksBetween }

procedure FCN_WeeksBetween.InitNode;
begin
  fcn := WeekSpan;
end;

{ FCN_MonthsBetween }

procedure FCN_MonthsBetween.InitNode;
begin
  fcn := MonthSpan;
end;

{ FCN_YearsBetween }

procedure FCN_YearsBetween.InitNode;
begin
  fcn := YearSpan;
end;

{ TTimeIntFcn }

procedure TTimeIntFcn.SimpleFunction;
var
  DateTime: TDateTime;
begin

  Args.Extract(DateTime, GetCurDateTime).Close;

  if Assigned(fcn16) then
    Result := ASOInt(fcn16(DateTime), IntFmt)
  else if Assigned(fcn32) then
    Result := ASOInt(fcn32(DateTime), IntFmt)
  else if Assigned(fcn64) then
    Result := ASOInt(fcn64(DateTime), IntFmt)
  else
    ErrInternal;

end;

{ FCN_DayOfTheWeek }

procedure FCN_DayOfTheWeek.InitNode;
begin
  fcn16 := DayOfTheWeek;
  IntFmt := fsDayOfWeek;
end;

{ FCN_DayOfTheMonth }

procedure FCN_DayOfTheMonth.InitNode;
begin
  fcn16 := DayOfTheMonth;
end;

{ FCN_DayOfTheYear }

procedure FCN_DayOfTheYear.InitNode;
begin
  fcn16 := DayOfTheYear;
end;

{ FCN_WeekOfTheYear }

procedure FCN_WeekOfTheYear.InitNode;
begin
  fcn16 := WeekOfTheYear;
end;

{ FCN_SecondOfTheDay }

procedure FCN_SecondOfTheDay.InitNode;
begin
  fcn32 := SecondOfTheDay;
end;

{ FCN_SecondOfTheWeek }

procedure FCN_SecondOfTheWeek.InitNode;
begin
  fcn32 := SecondOfTheWeek;
end;

{ FCN_SecondOfTheMonth }

procedure FCN_SecondOfTheMonth.InitNode;
begin
  fcn32 := SecondOfTheMonth;
end;

{ FCN_SecondOfTheYear }

procedure FCN_SecondOfTheYear.InitNode;
begin
  fcn32 := SecondOfTheYear;
end;

{ FCN_MillisecondOfTheDay }

procedure FCN_MillisecondOfTheDay.InitNode;
begin
  fcn32 := MillisecondOfTheDay;
end;

{ FCN_MillisecondOfTheWeek }

procedure FCN_MillisecondOfTheWeek.InitNode;
begin
  fcn32 := MillisecondOfTheWeek;
end;

{ FCN_MillisecondOfTheMonth }

procedure FCN_MillisecondOfTheMonth.InitNode;
begin
  fcn32 := MillisecondOfTheMonth;
end;

{ FCN_MillisecondOfTheYear }

procedure FCN_MillisecondOfTheYear.InitNode;
begin
  fcn64 := MillisecondOfTheYear;
end;

{ FCN_IsLeapYear }

procedure FCN_IsLeapYear.SimpleFunction;
var
  Year: Integer;
begin
  Args.ExtractNonNeg(Year).Close;
  Result := ASO(IsLeapYear(Year));
end;

{ FCN_DaysInYear }

procedure FCN_DaysInYear.SimpleFunction;
var
  Year: Integer;
begin
  Args.ExtractNonNeg(Year).Close;
  Result := ASOInt(DaysInAYear(Year));
end;

{ FCN_DaysInMonth }

procedure FCN_DaysInMonth.SimpleFunction;
var
  Year, Month: Integer;
begin
  Args.ExtractNonNeg(Year).ExtractNonNeg(Month).Close;
  Result := ASOInt(DaysInAMonth(Year, Month));
end;

{ FCN_Timestamp }

procedure FCN_Timestamp.DoExecute;

  function ChildIs(AFcn: TASFunctionClass): Boolean;
  begin
    Result := (Children[0] is AFcn) and
      Children[0].IsLeaf;
  end;

var
  DateTimeVal: TDateTime;
begin

  CheckNumArgs([0, 1]);

  case ChildCount of
    0:
      Result := ASO(GetCurDateTime);
    1:
      begin
        if ChildIs(FCN_Now) then
          Result := ASO(GetCurDateTime)
        else if ChildIs(FCN_Date) then
          Result := ASO(GetCurDate)
        else if ChildIs(FCN_Time) then
          Result := ASO(GetCurTime)
        else if ChildIs(FCN_DateTime) then
          Result := ASO(GetCurDateTime)
        else if ChildIs(FCN_Today) then
          Result := ASO(GetCurDate)
        else if ChildIs(FCN_Tomorrow) then
          Result := ASO(GetTomorrow)
        else if ChildIs(FCN_Yesterday) then
          Result := ASO(GetYesterday)
        else
        begin

          if not EvalChild(0) then Exit;

          if stTime.MatchingName(Args.PeekAt(0)) then
            Args.Extract(TTime(DateTimeVal)).Close
          else
            Args.Extract(DateTimeVal).Close;

          Result := ASO(TASR(DateTimeVal));

        end;
      end;
  end;

end;

{ FCN_Today }

procedure FCN_Today.SimpleFunction;
begin
  Args.Close;
  Result := ASODate(GetCurDate);
end;

{ FCN_Tomorrow }

procedure FCN_Tomorrow.SimpleFunction;
begin
  Args.Close;
  Result := ASODate(GetTomorrow);
end;

{ FCN_Yesterday }

procedure FCN_Yesterday.SimpleFunction;
begin
  Args.Close;
  Result := ASODate(GetYesterday);
end;

{ FCN_TruncateToMillisecond }

procedure FCN_TruncateToMillisecond.SimpleFunction;
var
  Arg: TAlgosimObject;
  x: TASR;
begin

  Args.Extract(Arg).Close;

  if (Arg is TAlgosimNumber) and Arg.TryToASR(x) then
    Result := ASO(RecodeTime(TDateTime(x), RecodeLeaveFieldAsIs,
      RecodeLeaveFieldAsIs, RecodeLeaveFieldAsIs, RecodeLeaveFieldAsIs))
  else if IsTypedStructure(Arg, stDateTime) then
    Args.MoveObject(Value)
  else
    ErrInvalidArguments;

end;

{ FCN_TruncateToSecond }

procedure FCN_TruncateToSecond.SimpleFunction;
var
  Arg: TAlgosimObject;
  x: TASR;
  DateTime, Time: TAlgosimStructure;
begin

  Args.Extract(Arg).Close;

  if (Arg is TAlgosimNumber) and Arg.TryToASR(x) then
    Result := ASO(RecodeTime(TDateTime(x), RecodeLeaveFieldAsIs,
      RecodeLeaveFieldAsIs, RecodeLeaveFieldAsIs, 0))
  else if IsTypedStructure(Arg, stDateTime) then
  begin
    Args.MoveObject<TAlgosimStructure>(Value, DateTime);
    Time := DateTime['time'] as TAlgosimStructure;
    Time['millisecond'] := ASOInt(0);
  end
  else
    ErrInvalidArguments;

end;

{ FCN_TruncateToMinute }

procedure FCN_TruncateToMinute.SimpleFunction;
var
  Arg: TAlgosimObject;
  x: TASR;
  DateTime, Time: TAlgosimStructure;
begin

  Args.Extract(Arg).Close;

  if (Arg is TAlgosimNumber) and Arg.TryToASR(x) then
    Result := ASO(RecodeTime(TDateTime(x), RecodeLeaveFieldAsIs,
      RecodeLeaveFieldAsIs, 0, 0))
  else if IsTypedStructure(Arg, stDateTime) then
  begin
    Args.MoveObject<TAlgosimStructure>(Value, DateTime);
    Time := DateTime['time'] as TAlgosimStructure;
    Time['second'] := ASOInt(0);
    Time['millisecond'] := ASOInt(0);
  end
  else
    ErrInvalidArguments;

end;

{ FCN_TruncateToHour }

procedure FCN_TruncateToHour.SimpleFunction;
var
  Arg: TAlgosimObject;
  x: TASR;
  DateTime, Time: TAlgosimStructure;
begin

  Args.Extract(Arg).Close;

  if (Arg is TAlgosimNumber) and Arg.TryToASR(x) then
    Result := ASO(RecodeTime(TDateTime(x), RecodeLeaveFieldAsIs, 0, 0, 0))
  else if IsTypedStructure(Arg, stDateTime) then
  begin
    Args.MoveObject<TAlgosimStructure>(Value, DateTime);
    Time := DateTime['time'] as TAlgosimStructure;
    Time['minute'] := ASOInt(0);
    Time['second'] := ASOInt(0);
    Time['millisecond'] := ASOInt(0);
  end
  else
    ErrInvalidArguments;

end;

{ FCN_TruncateToDay }

procedure FCN_TruncateToDay.SimpleFunction;
var
  Arg: TAlgosimObject;
  x: TASR;
  DateTime, Time: TAlgosimStructure;
begin

  Args.Extract(Arg).Close;

  if (Arg is TAlgosimNumber) and Arg.TryToASR(x) then
    Result := ASO(RecodeTime(TDateTime(x), 0, 0, 0, 0))
  else if IsTypedStructure(Arg, stDateTime) then
  begin
    Args.MoveObject<TAlgosimStructure>(Value, DateTime);
    Time := DateTime['time'] as TAlgosimStructure;
    Time['hour'] := ASOInt(0);
    Time['minute'] := ASOInt(0);
    Time['second'] := ASOInt(0);
    Time['millisecond'] := ASOInt(0);
  end
  else
    ErrInvalidArguments;

end;

{ FCN_TruncateToMonth }

procedure FCN_TruncateToMonth.SimpleFunction;
var
  Arg: TAlgosimObject;
  x: TASR;
  DateTime, Date, Time: TAlgosimStructure;
begin

  Args.Extract(Arg).Close;

  if (Arg is TAlgosimNumber) and Arg.TryToASR(x) then
    Result := ASO(RecodeDateTime(TDateTime(x),
      RecodeLeaveFieldAsIs, RecodeLeaveFieldAsIs, 1, 0, 0, 0, 0))
  else if IsTypedStructure(Arg, stDateTime) then
  begin
    Args.MoveObject<TAlgosimStructure>(Value, DateTime);
    Date := DateTime['date'] as TAlgosimStructure;
    Time := DateTime['time'] as TAlgosimStructure;
    Date['day'] := ASOInt(1);
    Time['hour'] := ASOInt(0);
    Time['minute'] := ASOInt(0);
    Time['second'] := ASOInt(0);
    Time['millisecond'] := ASOInt(0);
  end
  else
    ErrInvalidArguments;

end;

{ FCN_TruncateToYear }

procedure FCN_TruncateToYear.SimpleFunction;
var
  Arg: TAlgosimObject;
  x: TASR;
  DateTime, Date, Time: TAlgosimStructure;
begin

  Args.Extract(Arg).Close;

  if (Arg is TAlgosimNumber) and Arg.TryToASR(x) then
    Result := ASO(RecodeDateTime(TDateTime(x),
      RecodeLeaveFieldAsIs, 1, 1, 0, 0, 0, 0))
  else if IsTypedStructure(Arg, stDateTime) then
  begin
    Args.MoveObject<TAlgosimStructure>(Value, DateTime);
    Date := DateTime['date'] as TAlgosimStructure;
    Time := DateTime['time'] as TAlgosimStructure;
    Date['month'] := ASOInt(1, fsMonth);
    Date['day'] := ASOInt(1);
    Time['hour'] := ASOInt(0);
    Time['minute'] := ASOInt(0);
    Time['second'] := ASOInt(0);
    Time['millisecond'] := ASOInt(0);
  end
  else
    ErrInvalidArguments;

end;

{ FCN_NumDigits }

procedure FCN_NumDigits.DoExecute;
var
  Arg: TAlgosimNumericEntity;
begin
  CheckNumArgs(1);
  if not ExtractRef<TAlgosimNumericEntity>(0, Arg) then Exit;
  Result := ASOInt(Arg.NumDigits);
end;

{ FCN_MinLength }

procedure FCN_MinLength.DoExecute;
var
  Arg: TAlgosimNumericEntity;
begin
  CheckNumArgs(1);
  if not ExtractRef<TAlgosimNumericEntity>(0, Arg) then Exit;
  Result := ASOInt(Arg.MinLength);
end;

{ FCN_NumberFormat }

procedure FCN_NumberFormat.DoExecute;
var
  Arg: TAlgosimNumericEntity;
begin
  CheckNumArgs(1);
  if not ExtractRef<TAlgosimNumericEntity>(0, Arg) then Exit;
  if Arg.NumberFormatOverride then
    case Arg.NumberFormat of
      nfDefault:
        Result := ASO('default');
      nfFixed:
        Result := ASO('fixed');
      nfExponent:
        Result := ASO('scientific');
      nfDefExp:
        Result := ASO('power');
    else
      Result := ASO('unknown');
    end
  else
    Result := ASO('inherited');
end;

{ FCN_NumberBase }

procedure FCN_NumberBase.DoExecute;
var
  Arg: TAlgosimNumericEntity;
begin
  CheckNumArgs(1);
  if not ExtractRef<TAlgosimNumericEntity>(0, Arg) then Exit;
  Result := ASOInt(Arg.NumberBase);
end;

{ FCN_FormatStyle }

procedure FCN_FormatStyle.DoExecute;
var
  Arg: TAlgosimNumericEntity;
begin
  CheckNumArgs(1);
  if not ExtractRef<TAlgosimNumericEntity>(0, Arg) then Exit;
  Result := ASO(Arg.Style.ToString);
end;

{ FCN_DigitGrouping }

procedure FCN_DigitGrouping.DoExecute;
var
  Arg: TAlgosimNumericEntity;
begin
  CheckNumArgs(1);
  if not ExtractRef<TAlgosimNumericEntity>(0, Arg) then Exit;
  if Arg.DigitGroupingOverride then
    Result := ASOInt(Arg.DigitGrouping)
  else
    Result := ASOInt(-1)
end;

{ FCN_PrettyExp }

procedure FCN_PrettyExp.DoExecute;
var
  Arg: TAlgosimNumericEntity;
begin
  CheckNumArgs(1);
  if not ExtractRef<TAlgosimNumericEntity>(0, Arg) then Exit;
  if Arg.PrettyExpOverride then
    Result := ASO(Arg.PrettyExp)
  else
    Result := ASO('inherited')
end;

{ FCN_MaxLen }

procedure FCN_MaxLen.DoExecute;
var
  Obj: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Obj) then Exit;
  Result := ASOInt(Obj.MaxLen);
end;

{ FCN_SetNumDigits }

procedure FCN_SetNumDigits.SimpleFunction;
var
  N: Integer;
  NE: TAlgosimNumericEntity;
begin
  Args.MoveObject<TAlgosimNumericEntity>(Value, NE).Extract(N).Close;
  NE.NumDigitsOverride := N >= 0;
  if NE.NumDigitsOverride then
    NE.NumDigits := N;
end;

{ FCN_SetMinLength }

procedure FCN_SetMinLength.SimpleFunction;
var
  N: Integer;
  NE: TAlgosimNumericEntity;
begin
  Args.MoveObject<TAlgosimNumericEntity>(Value, NE).ExtractNonNeg(N).Close;
  NE.MinLength := N;
end;

{ FCN_SetNumberFormat }

procedure FCN_SetNumberFormat.SimpleFunction;
const
  NumberFormats: array[0..4] of string = ('inherited', 'default', 'fraction', 'fixed', 'scientific');
var
  s: string;
  NE: TAlgosimNumericEntity;
begin
  Args.MoveObject<TAlgosimNumericEntity>(Value, NE).Extract(s, NumberFormats).Close;
  case IndexText(s, NumberFormats) of
    0:
      NE.NumberFormatOverride := False;
    1:
      begin
        NE.NumberFormatOverride := True;
        NE.NumberFormat := nfDefault;
      end;
    2:
      begin
        NE.NumberFormatOverride := True;
        NE.NumberFormat := nfFraction;
      end;
    3:
      begin
        NE.NumberFormatOverride := True;
        NE.NumberFormat := nfFixed;
      end;
    4:
      begin
        NE.NumberFormatOverride := True;
        NE.NumberFormat := nfExponent;
      end;
  end;
end;

{ FCN_SetNumberBase }

procedure FCN_SetNumberBase.SimpleFunction;
var
  N: Integer;
  NE: TAlgosimNumericEntity;
begin
  Args.MoveObject<TAlgosimNumericEntity>(Value, NE).ExtractNonNeg(N).Close;
  NE.NumberBase := N;
end;

{ FCN_SetFormatStyle }

procedure FCN_SetFormatStyle.SimpleFunction;
var
  Style: string;
  NE: TAlgosimNumericEntity;
begin
  Args.MoveObject<TAlgosimNumericEntity>(Value, NE).Extract(Style).Close;
  NE.Style := TFormatStyle.FromString(Style);
end;

{ FCN_SetDigitGrouping }

procedure FCN_SetDigitGrouping.SimpleFunction;
var
  N: Integer;
  NE: TAlgosimNumericEntity;
begin
  Args.MoveObject<TAlgosimNumericEntity>(Value, NE).Extract(N).Close;
  NE.DigitGroupingOverride := N >= 0;
  if NE.DigitGroupingOverride then
    NE.DigitGrouping := N;
end;

{ FCN_SetPrettyExp }

procedure FCN_SetPrettyExp.SimpleFunction;
var
  b: Boolean;
  s: string;
  NE: TAlgosimNumericEntity;
begin
  if Args.PeekAt(1) is TAlgosimString then
  begin
    Args.MoveObject<TAlgosimNumericEntity>(Value, NE).Extract(s, ['inherited']).Close;
    NE.PrettyExpOverride := False;
  end
  else
  begin
    Args.MoveObject<TAlgosimNumericEntity>(Value, NE).Extract(b).Close;
    NE.PrettyExpOverride := True;
    NE.PrettyExp := b;
  end;
end;

{ FCN_SetMaxLen }

procedure FCN_SetMaxLen.SimpleFunction;
var
  N: Integer;
begin
  Args.MoveObject(Value).ExtractNonNeg(N).Close;
  Value.MaxLen := N;
end;

{ FCN_AsSingleLine }

procedure FCN_AsSingleLine.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASO(Arg.GetAsSingleLineText(Context.FormatOptions));
end;

{ FCN_InputForm }

procedure FCN_InputForm.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASO(Arg.ToInputString);
end;

{ FCN_AsMultiLine }

procedure FCN_AsMultiLine.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASO(Arg.GetAsMultiLineText(Context.FormatOptions));
end;

{ FCN_SaveToFile }

procedure FCN_SaveToFile.DoExecute;
var
  Obj: TAlgosimObject;
  FileName: string;
begin
  CheckNumArgsAtLeast(1);
  if not ExtractRef(0, Obj) then Exit;
  if not EvalChildren(1) then Exit;
  var Options := Args.Skip.Extract(FileName, '').ExtractStruct;
  try
    var ContextObj := TExecutionContextRefObject.Create(Context);
    try
      if FileName.IsEmpty then
        Context.Perform(CLIENT_COMMAND_SAVEOBJECT, NativeInt(Obj), 0, NativeInt(Options))
      else
        Obj.SaveToFile(FileName, Options, ContextObj);
    finally
      ContextObj.Free;
    end;
    Result := ASO(success);
  finally
    Options.Free;
  end;
end;

{ FCN_LoadFromFile }

procedure FCN_LoadFromFile.SimpleFunction;
var
  FileName, ClassTypeName: string;
  classpair: TPair<TAlgosimObjectClass, TAlgosimObjectClassData>;
begin

  Args.Extract(FileName).Extract(ClassTypeName, 'object').Close;

  for classpair in TAlgosimObject._ASOClassData do
    if classpair.Value.ClassTypeName.Equals(ClassTypeName) then
    begin
      Result := classpair.Key.LoadFromFile(FileName);
      Exit;
    end;

  raise EAlgosimObjectException.CreateFmt(SUnknownClassType, [ClassTypeName]);

end;

{ FCN_CopyToClipboard }

procedure FCN_CopyToClipboard.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Arg.CopyToClipboard;
  Result := ASO(success);
end;

{ FCN_Flatten }

procedure FCN_Flatten.SimpleFunction;
var
  Obj: TAlgosimArray;
begin
  Args.Extract(Obj).Close;
  Result := Obj.PickRecursive(
    function(AMember: TAlgosimObject): Boolean
    begin
      Result := not AMember.IsObjectContainer;
    end
  );
end;

{ FCN_Group }

procedure FCN_Group.SimpleFunction;
var
  N: Integer;
  Arr: TAlgosimArray;
begin
  Args.MoveObject<TAlgosimArray>(Value, Arr).ExtractPos(N).Close;
  Arr.Group(N);
end;

{ FCN_Variable }

procedure FCN_Variable.fcn(const ASymbolName: string);
var
  Variable: TAlgosimVariable;
begin
  if Context.TryGetVariable(ASymbolName, Variable) then
    Result := Variable.CreateStructure
  else
    raise EUnknownIdentifier.CreateFmt(SUnknownIdentifier, [ASymbolName]);
end;

{ FCN_Object }

procedure FCN_Object.fcn(const ASymbolName: string);
begin
  Context.GetValue(ASymbolName, Value);
end;

{ FCN_Metadata }

procedure FCN_Metadata.fcn(const ASymbolName: string);
var
  Variable: TAlgosimVariable;
begin
  if Context.TryGetVariable(ASymbolName, Variable) then
    Result := Variable.CreateMetadataStructure
  else
    raise EUnknownIdentifier.CreateFmt(SUnknownIdentifier, [ASymbolName]);
end;

{ FCN_Description }

procedure FCN_Description.fcn(const ASymbolName: string);
var
  Variable: TAlgosimVariable;
begin
  if Context.TryGetVariable(ASymbolName, Variable) then
    Result := ASO(Variable.Description)
  else
    raise EUnknownIdentifier.CreateFmt(SUnknownIdentifier, [ASymbolName]);
end;

{ FCN_Delete }

procedure FCN_Delete.fcn(const ASymbolName: string);
begin
  if Context.TryRemoveVariable(ASymbolName) then
    Result := ASO(success)
  else
    raise EUnknownIdentifier.CreateFmt(SUnknownIdentifier, [ASymbolName])
end;

{ FCN_Protect }

procedure FCN_Protect.fcn(const ASymbolName: string);
var
  Variable: TAlgosimVariable;
begin
  if Context.TryGetVariable(ASymbolName, Variable) then
  begin
    Variable.IsProtected := True;
    Result := ASO(success);
  end
  else
    raise EUnknownIdentifier.CreateFmt(SUnknownIdentifier, [ASymbolName]);
end;

{ FCN_Unprotect }

procedure FCN_Unprotect.fcn(const ASymbolName: string);
var
  Variable: TAlgosimVariable;
begin
  if Context.TryGetVariable(ASymbolName, Variable) then
  begin
    Variable.IsProtected := False;
    Result := ASO(success);
  end
  else
    raise EUnknownIdentifier.CreateFmt(SUnknownIdentifier, [ASymbolName]);
end;

{ FCN_Assign }

procedure FCN_Assign.DoExecute;
resourcestring
  SMultipleAssignmentCountMismatch = 'The number of symbols (%d) doesn''t match the number of values (%d) in multiple assignment expression.';
var
  LB, RB: Boolean;
  i: Integer;
  LValueData: TLValueData;
  AL: TAlgosimAssignmentList;
const
  LEFT = 0;
  RIGHT = 1;
begin

  CheckNumArgs(2);

  LB := IsBifurcation(Children[LEFT]);
  RB := IsBifurcation(Children[RIGHT]);

  if not LB or not RB then
    raise EExpressionException.Create('Assignment node without list children.');


  if Children[RIGHT].ChildCount = 1 then
  begin

    if not EvalChild(RIGHT) then Exit;

    if Children[RIGHT].Value is TAlgosimAssignmentList then
      AL := TAlgosimAssignmentList(Children[RIGHT].Value)
    else
      AL := nil;

    if Assigned(AL) then
      if Children[LEFT].ChildCount <> AL.ValueCount then
        raise EInvArgs.CreateFmt(SMultipleAssignmentCountMismatch,
          [Children[LEFT].ChildCount, AL.ElementCount]);

    for i := 0 to Children[LEFT].ChildCount - 1 do
    begin

      if not GetLValue(Children[LEFT].Children[i], LValueData) then
        raise EIllegalLValue.Create(SLeftSideCannotBeAssignedTo);

      try
        if Assigned(AL) then
          Context.SaveVariable(LValueData, AL.Elements[i + 1].Clone)
        else
          Context.SaveVariable(LValueData, Children[RIGHT].Value.Clone);
      finally
        LValueData.Free;
      end;

    end;

    TMover<TAlgosimObject>.Move(Value, Children[RIGHT].Value);

  end
  else
  begin

    if Children[LEFT].ChildCount <> Children[RIGHT].ChildCount then
      raise EInvArgs.CreateFmt(SMultipleAssignmentCountMismatch,
        [Children[LEFT].ChildCount, Children[RIGHT].ChildCount]);

    if not Children[RIGHT].EvalChildren then // cannot eval Children[Right] because then the last grandchild will be moved to the child's value
    begin
      TMover<TAlgosimObject>.Move(Value, Children[RIGHT].Value);
      Exit;
    end;

    for i := 0 to Children[LEFT].ChildCount - 1 do
    begin

      if not GetLValue(Children[LEFT].Children[i], LValueData) then
        raise EIllegalLValue.Create(SLeftSideCannotBeAssignedTo);

      try
        Context.SaveVariable(LValueData, Children[RIGHT].Children[i].Value.Clone);
      finally
        LValueData.Free;
      end;

    end;

    if Children[RIGHT].ChildCount > 0 then
      TMover<TAlgosimObject>.Move(Value,
        Children[RIGHT].Children[Children[RIGHT].ChildCount - 1].Value)
    else
      Value := ASO(null);

  end;

end;

{ FCN_Cls }

procedure FCN_Cls.SimpleFunction;
var
  BufName: string;
begin
  CheckNumArgs([0, 1]);
  case Args.Count of
    0:
      begin
        Args.Close;
        Context.Perform(CLIENT_COMMAND_CLS);
      end;
    1:
      begin
        Args.Extract(BufName).Close;
        Context.ClearBuffer(BufName);
        Context.Perform(CLIENT_COMMAND_CLS, NativeInt(PChar(BufName)));
      end
  else
    ErrInvalidArguments;
  end;
end;

{ FCN_Exit }

procedure FCN_Exit.DoExecute;
begin
  CheckNumArgs(0);
  Context.Perform(CLIENT_COMMAND_EXIT);
  Result := ASOBreak(Integer.MaxValue);
end;

{ FCN_Fail }

procedure FCN_Fail.SimpleFunction;
begin
  if Args.Count > 0 then
    Result := ASO(failure, Args.PeekAt(0).ToString)
  else
    Result := ASO(failure)
end;

{ FCN_Assert }

procedure FCN_Assert.SimpleFunction;
var
  Condition: Boolean;
  Str: string;
begin

  Args.Extract(Condition).Extract(Str, '').Close;

  if Condition then
    Result := ASO(null)
  else
    Result := ASO(failure, Str);

end;

{ FCN_Succeeded }

procedure FCN_Succeeded.DoExecute;
begin
  CheckNumArgs(1);
  Children[0].Evaluate;
  Result := ASO(not IsFailure(Children[0].Value));
end;

{ FCN_Try }

procedure FCN_Try.DoExecute;
begin

  CheckNumArgs([1, 2]);

  case Args.Count of
    1:
      begin
        Children[0].Evaluate;
        if IsFailure(Children[0].Value) then
          Result := ASO(null)
        else
          TMover<TAlgosimObject>.Move(Value, Children[0].Value);
      end;
    2:
      begin
        Children[0].Evaluate;
        if IsFailure(Children[0].Value) then
        begin
          if not EvalChild(1) then Exit;
          TMover<TAlgosimObject>.Move(Value, Children[1].Value)
        end
        else
          TMover<TAlgosimObject>.Move(Value, Children[0].Value);
      end;
  else
    ErrInvalidArguments;
  end;

end;

{ FCN_Piecewise }

procedure FCN_Piecewise.DoExecute;
resourcestring
  SPiecewiseOddNumArgs = 'Odd number of arguments passed to function "piecewise".';
var
  i, PartCount: Integer;
  ExpressionIndex, ConditionIndex: Integer;
  Condition: Boolean;
begin

  if Odd(ChildCount) then
    raise EInvArgs.Create(SPiecewiseOddNumArgs);

  PartCount := ChildCount div 2;

  for i := 0 to PartCount - 1 do
  begin

    ExpressionIndex := 2 * i;
    ConditionIndex := 2 * i + 1;

    if not EvalChild(ConditionIndex) then Exit;
    Args(ConditionIndex).Extract(Condition);

    if Condition then
    begin
      Children[ExpressionIndex].Evaluate;
      TMover<TAlgosimObject>.Move(Value, Children[ExpressionIndex].Value);
      Exit;
    end;

  end;

  Result := ASO(null);

end;

{ FCN_MakeMember }

procedure FCN_MakeMember.SimpleFunction;
var
  Name: string;
  ValObj: TAlgosimObject;
begin
  Args.Extract(Name).MoveObject(ValObj).Close;
  Result := stStructMember.New( {noexcept}
    [
      sm('name', ASO(Name)),
      sm('value', ValObj)
    ]);
end;

{ FCN_MakeStruct }

procedure FCN_MakeStruct.SimpleFunction;
var
  i: Integer;
  Member: TAlgosimTypedStructure;
  Name: string;
  Val: TAlgosimObject;
  Args: TArgumentExtractor;
begin
  Args := Self.Args;
  Result := TAlgosimStructure.Create;
  Result.Capacity := ChildCount;
  for i := 0 to ChildCount - 1 do
  begin
    Args := Args.Extract(Member);
    stStructMember.ValidateAgainst(Member);
    Name := Member.Values['name'].ToString;
    Val := Member.Values['value'];
    Member.Release('value');
    TAlgosimStructure(Result).Add(Name, Val);
  end;
end;

{ FCN_System }

procedure FCN_System.SimpleFunction;
var
  Cmd, Params: string;
begin
  Args.Extract(Cmd).Extract(Params, '').Close;
  Result := TAlgosimSuccessIndication.CreateWithValue(
    Context.Perform(CLIENT_COMMAND_SYSTEM,
      NativeInt(PChar(Cmd)), NativeInt(PChar(Params))));
end;

{ FCN_RotLeft }

procedure FCN_RotLeft.SimpleFunction;
var
  Arg: TAlgosimObject;
  N: Integer;
begin
  Args.Extract(Arg).Extract(N, 1).Close;
  Result := Arg.RotLeft(N);
end;

{ FCN_RotRight }

procedure FCN_RotRight.SimpleFunction;
var
  Arg: TAlgosimObject;
  N: Integer;
begin
  Args.Extract(Arg).Extract(N, 1).Close;
  Result := Arg.RotRight(N);
end;

{ FCN_Diag }

procedure FCN_Diag.SimpleFunction;
var
  obj: TAlgosimObject;
begin

  if Args.Count = 1 then
  begin
    Args.Extract(Obj).Close;
    if Obj.IsComplex then
      Result := ASO(TComplexMatrix.CreateDiagonal(Obj.AsComplexVector))
    else
      Result := ASO(TRealMatrix.CreateDiagonal(Obj.AsRealVector))
  end
  else
  begin
    if HasComplexArg then
      Result := ASO(TComplexMatrix.CreateDiagonal(Args.ExtractComplexNumbers))
    else
      Result := ASO(TRealMatrix.CreateDiagonal(Args.ExtractRealNumbers))
  end;

end;

{ FCN_Row }

function FCN_Row.BuildLValue(LValueData: TLValueData): Boolean;
var
  IntIdx: Integer;
begin
  Result := ChildCount = 2;
  if Result then
  begin
    Children[1].Evaluate;
    if not (Children[1].Value is TAlgosimNumber) or not Children[1].Value.TryToInt32(IntIdx) then
      Exit(False);
    LValueData.Add(TLValuePathItem.Create(skRowIndex, IntIdx));
    Result := Children[0].BuildLValue(LValueData);
  end;
end;

procedure FCN_Row.DoExecute;
var
  Arg: TAlgosimObject;
  N: Integer;
begin
  CheckNumArgs(2);
  if not ExtractRef(0, Arg) then Exit;
  if not EvalChild(1) then Exit;
  Args.Skip.ExtractPos(N).Close;
  Result := Arg.Row(N);
end;

function FCN_Row.LValuePart: Boolean;
begin
  Result := True;
end;

{ FCN_Col }

function FCN_Col.BuildLValue(LValueData: TLValueData): Boolean;
var
  IntIdx: Integer;
begin
  Result := ChildCount = 2;
  if Result then
  begin
    Children[1].Evaluate;
    if not (Children[1].Value is TAlgosimNumber) or not Children[1].Value.TryToInt32(IntIdx) then
      Exit(False);
    LValueData.Add(TLValuePathItem.Create(skColIndex, IntIdx));
    Result := Children[0].BuildLValue(LValueData);
  end;
end;

procedure FCN_Col.DoExecute;
var
  Arg: TAlgosimObject;
  N: Integer;
begin
  CheckNumArgs(2);
  if not ExtractRef(0, Arg) then Exit;
  if not EvalChild(1) then Exit;
  Args.Skip.ExtractPos(N).Close;
  Result := Arg.Column(N);
end;

function FCN_Col.LValuePart: Boolean;
begin
  Result := True;
end;

{ FCN_Rows }

procedure FCN_Rows.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := Arg.Rows;
end;

{ FCN_Cols }

procedure FCN_Cols.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := Arg.Columns;
end;

{ FCN_MainDiagonal }

function FCN_MainDiagonal.BuildLValue(LValueData: TLValueData): Boolean;
begin
  Result := ChildCount = 1;
  if Result then
  begin
    LValueData.Add(TLValuePathItem.Create(skMainDiagonal));
    Result := Children[0].BuildLValue(LValueData);
  end;
end;

procedure FCN_MainDiagonal.DoExecute;
var
  Arg: TAlgosimMatrix;
begin
  CheckNumArgs(1);
  if not ExtractRef<TAlgosimMatrix>(0, Arg) then Exit;
  Result := Arg.MainDiagonal;
end;

function FCN_MainDiagonal.LValuePart: Boolean;
begin
  Result := True;
end;

{ FCN_Superdiagonal }

function FCN_Superdiagonal.BuildLValue(LValueData: TLValueData): Boolean;
begin
  Result := ChildCount = 1;
  if Result then
  begin
    LValueData.Add(TLValuePathItem.Create(skSuperdiagonal));
    Result := Children[0].BuildLValue(LValueData);
  end;
end;

procedure FCN_Superdiagonal.DoExecute;
var
  Arg: TAlgosimMatrix;
begin
  CheckNumArgs(1);
  if not ExtractRef<TAlgosimMatrix>(0, Arg) then Exit;
  Result := Arg.Superdiagonal;
end;

function FCN_Superdiagonal.LValuePart: Boolean;
begin
  Result := True;
end;

{ FCN_Subdiagonal }

function FCN_Subdiagonal.BuildLValue(LValueData: TLValueData): Boolean;
begin
  Result := ChildCount = 1;
  if Result then
  begin
    LValueData.Add(TLValuePathItem.Create(skSubdiagonal));
    Result := Children[0].BuildLValue(LValueData);
  end;
end;

procedure FCN_Subdiagonal.DoExecute;
var
  Arg: TAlgosimMatrix;
begin
  CheckNumArgs(1);
  if not ExtractRef<TAlgosimMatrix>(0, Arg) then Exit;
  Result := Arg.Subdiagonal;
end;

function FCN_Subdiagonal.LValuePart: Boolean;
begin
  Result := True;
end;

{ FCN_AntiDiagonal }

function FCN_Antidiagonal.BuildLValue(LValueData: TLValueData): Boolean;
begin
  Result := ChildCount = 1;
  if Result then
  begin
    LValueData.Add(TLValuePathItem.Create(skAntidiagonal));
    Result := Children[0].BuildLValue(LValueData);
  end;
end;

procedure FCN_Antidiagonal.DoExecute;
var
  Arg: TAlgosimMatrix;
begin
  CheckNumArgs(1);
  if not ExtractRef<TAlgosimMatrix>(0, Arg) then Exit;
  Result := Arg.Antidiagonal;
end;

function FCN_Antidiagonal.LValuePart: Boolean;
begin
  Result := True;
end;

{ FCN_ReplaceRow }

procedure FCN_ReplaceRow.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  N: Integer;
  Vect: TAlgosimVector;
  CM: TComplexMatrix;
  CV: TComplexVector;
  RM: TRealMatrix;
  RV: TRealVector;
begin
  Args.Extract(Mat).ExtractPos(N).Extract(Vect).Close;
  if not InRange(N, 1, Mat.PlanarExtent.cy) then
    raise EAlgosimObjectException.CreateFmt(SIndexOutOfBounds, [N]);
  if HasComplexArg then
  begin
    CM := Mat.AsComplexMatrix;
    CV := Vect.AsComplexVector;
    CM.Rows[N - 1] := CV;
    Result := ASO(CM);
  end
  else
  begin
    RM := Mat.AsRealMatrix;
    RV := Vect.AsRealVector;
    RM.Rows[N - 1] := RV;
    Result := ASO(RM);
  end;
end;

{ FCN_ReplaceCol }

procedure FCN_ReplaceCol.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  N: Integer;
  Vect: TAlgosimVector;
  CM: TComplexMatrix;
  CV: TComplexVector;
  RM: TRealMatrix;
  RV: TRealVector;
begin
  Args.Extract(Mat).ExtractPos(N).Extract(Vect).Close;
  if not InRange(N, 1, Mat.PlanarExtent.cx) then
    raise EAlgosimObjectException.CreateFmt(SIndexOutOfBounds, [N]);
  if HasComplexArg then
  begin
    CM := Mat.AsComplexMatrix;
    CV := Vect.AsComplexVector;
    CM.Cols[N - 1] := CV;
    Result := ASO(CM);
  end
  else
  begin
    RM := Mat.AsRealMatrix;
    RV := Vect.AsRealVector;
    RM.Cols[N - 1] := RV;
    Result := ASO(RM);
  end;
end;

{ FCN_ReplaceDiagonal }

procedure FCN_ReplaceDiagonal.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Vect: TAlgosimVector;
  CM: TComplexMatrix;
  CV: TComplexVector;
  RM: TRealMatrix;
  RV: TRealVector;
begin
  Args.Extract(Mat).Extract(Vect).Close;
  if HasComplexArg then
  begin
    CM := Mat.AsComplexMatrix;
    CV := Vect.AsComplexVector;
    CM.MainDiagonal := CV;
    Result := ASO(CM);
  end
  else
  begin
    RM := Mat.AsRealMatrix;
    RV := Vect.AsRealVector;
    RM.MainDiagonal := RV;
    Result := ASO(RM);
  end;
end;

{ FCN_ReplaceSuperdiagonal }

procedure FCN_ReplaceSuperdiagonal.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Vect: TAlgosimVector;
  CM: TComplexMatrix;
  CV: TComplexVector;
  RM: TRealMatrix;
  RV: TRealVector;
begin
  Args.Extract(Mat).Extract(Vect).Close;
  if HasComplexArg then
  begin
    CM := Mat.AsComplexMatrix;
    CV := Vect.AsComplexVector;
    CM.Superdiagonal := CV;
    Result := ASO(CM);
  end
  else
  begin
    RM := Mat.AsRealMatrix;
    RV := Vect.AsRealVector;
    RM.Superdiagonal := RV;
    Result := ASO(RM);
  end;
end;

{ FCN_ReplaceSubdiagonal }

procedure FCN_ReplaceSubdiagonal.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Vect: TAlgosimVector;
  CM: TComplexMatrix;
  CV: TComplexVector;
  RM: TRealMatrix;
  RV: TRealVector;
begin
  Args.Extract(Mat).Extract(Vect).Close;
  if HasComplexArg then
  begin
    CM := Mat.AsComplexMatrix;
    CV := Vect.AsComplexVector;
    CM.Subdiagonal := CV;
    Result := ASO(CM);
  end
  else
  begin
    RM := Mat.AsRealMatrix;
    RV := Vect.AsRealVector;
    RM.Subdiagonal := RV;
    Result := ASO(RM);
  end;
end;

{ FCN_ReplaceAntidiagonal }

procedure FCN_ReplaceAntidiagonal.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Vect: TAlgosimVector;
  CM: TComplexMatrix;
  CV: TComplexVector;
  RM: TRealMatrix;
  RV: TRealVector;
begin
  Args.Extract(Mat).Extract(Vect).Close;
  if HasComplexArg then
  begin
    CM := Mat.AsComplexMatrix;
    CV := Vect.AsComplexVector;
    CM.Antidiagonal := CV;
    Result := ASO(CM);
  end
  else
  begin
    RM := Mat.AsRealMatrix;
    RV := Vect.AsRealVector;
    RM.Antidiagonal := RV;
    Result := ASO(RM);
  end;
end;

{ FCN_IsRow }

procedure FCN_IsRow.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASO(Arg.PlanarExtent.cy = 1);
end;

{ FCN_IsCol }

procedure FCN_IsCol.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := ASO(Arg.PlanarExtent.cx = 1);
end;

{ FCN_IsSquare }

procedure FCN_IsSquare.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
    with Arg.PlanarExtent do
      Result := ASO(cx = cy);
end;

{ TMatrixEpsilonFunction<T> }

procedure TMatrixEpsilonFunction<T>.DoExecute;
var
  Mat: TAlgosimMatrix;
  Eps: TASR;
  Method: TEpsilonFcn;
begin

  CheckNumArgs([1, 2]);
  if not ExtractRef<TAlgosimMatrix>(0, Mat) then Exit;
  if not EvalChildren(1) then Exit;

  Args.Skip.ExtractNonNeg(Eps, 0).Close;

  if Mat is TAlgosimRealMatrix then
  begin
    Method := rfcn;
    TMethod(Method).Data := @TAlgosimRealMatrix(Mat).Value;
    generic_result := Method(Eps)
  end
  else if Mat is TAlgosimComplexMatrix then
  begin
    Method := cfcn;
    TMethod(Method).Data := @TAlgosimComplexMatrix(Mat).Value;
    generic_result := Method(Eps)
  end
  else
    ErrInvalidArguments;

end;

{ TMatrixQueryWithEpsilon }

procedure TMatrixQueryWithEpsilon.DoExecute;
begin
  inherited;
  Result := ASO(generic_result);
end;

{ FCN_IsIdentity }

procedure FCN_IsIdentity.InitNode;
begin
  rfcn := _TRealMatrix.IsIdentity;
  cfcn := _TComplexMatrix.IsIdentity;
end;

{ FCN_IsZeroMatrix }

procedure FCN_IsZeroMatrix.InitNode;
begin
  rfcn := _TRealMatrix.IsZeroMatrix;
  cfcn := _TComplexMatrix.IsZeroMatrix;
end;

{ FCN_IsDiagonal }

procedure FCN_IsDiagonal.InitNode;
begin
  rfcn := _TRealMatrix.IsDiagonal;
  cfcn := _TComplexMatrix.IsDiagonal;
end;

{ FCN_IsAntiDiagonal }

procedure FCN_IsAntiDiagonal.InitNode;
begin
  rfcn := _TRealMatrix.IsAntiDiagonal;
  cfcn := _TComplexMatrix.IsAntiDiagonal;
end;

{ FCN_IsReversal }

procedure FCN_IsReversal.InitNode;
begin
  rfcn := _TRealMatrix.IsReversal;
  cfcn := _TComplexMatrix.IsReversal;
end;

{ FCN_IsUpperTriangular }

procedure FCN_IsUpperTriangular.InitNode;
begin
  rfcn := _TRealMatrix.IsUpperTriangular;
  cfcn := _TComplexMatrix.IsUpperTriangular;
end;

{ FCN_IsLowerTriangular }

procedure FCN_IsLowerTriangular.InitNode;
begin
  rfcn := _TRealMatrix.IsLowerTriangular;
  cfcn := _TComplexMatrix.IsLowerTriangular;
end;

{ FCN_IsTriangular }

procedure FCN_IsTriangular.InitNode;
begin
  rfcn := _TRealMatrix.IsTriangular;
  cfcn := _TComplexMatrix.IsTriangular;
end;

{ FCN_IsRowEchelonForm }

procedure FCN_IsRowEchelonForm.InitNode;
begin
  rfcn := _TRealMatrix.IsRowEchelonForm;
  cfcn := _TComplexMatrix.IsRowEchelonForm;
end;

{ FCN_IsReducedRowEchelonForm }

procedure FCN_IsReducedRowEchelonForm.InitNode;
begin
  rfcn := _TRealMatrix.IsReducedRowEchelonForm;
  cfcn := _TComplexMatrix.IsReducedRowEchelonForm;
end;

{ FCN_IsScalar }

procedure FCN_IsScalar.InitNode;
begin
  rfcn := _TRealMatrix.IsScalar;
  cfcn := _TComplexMatrix.IsScalar;
end;

{ FCN_IsSymmetric }

procedure FCN_IsSymmetric.InitNode;
begin
  rfcn := _TRealMatrix.IsSymmetric;
  cfcn := _TComplexMatrix.IsSymmetric;
end;

{ FCN_IsSkewSymmetric }

procedure FCN_IsSkewSymmetric.InitNode;
begin
  rfcn := _TRealMatrix.IsSkewSymmetric;
  cfcn := _TComplexMatrix.IsSkewSymmetric;
end;

{ FCN_IsHermitian }

procedure FCN_IsHermitian.InitNode;
begin
  rfcn := _TRealMatrix.IsSymmetric;
  cfcn := _TComplexMatrix.IsHermitian;
end;

{ FCN_IsSkewHermitian }

procedure FCN_IsSkewHermitian.InitNode;
begin
  rfcn := _TRealMatrix.IsSkewSymmetric;
  cfcn := _TComplexMatrix.IsSkewHermitian;
end;

{ FCN_IsOrthogonal }

procedure FCN_IsOrthogonal.InitNode;
begin
  rfcn := _TRealMatrix.IsOrthogonal;
  cfcn := _TComplexMatrix.IsOrthogonal;
end;

{ FCN_IsUnitary }

procedure FCN_IsUnitary.InitNode;
begin
  rfcn := _TRealMatrix.IsOrthogonal;
  cfcn := _TComplexMatrix.IsUnitary;
end;

{ FCN_IsNormal }

procedure FCN_IsNormal.InitNode;
begin
  rfcn := _TRealMatrix.IsNormal;
  cfcn := _TComplexMatrix.IsNormal;
end;

{ FCN_IsBinary }

procedure FCN_IsBinary.InitNode;
begin
  rfcn := _TRealMatrix.IsBinary;
  cfcn := _TComplexMatrix.IsBinary;
end;

{ FCN_IsPermutation }

procedure FCN_IsPermutation.InitNode;
begin
  rfcn := _TRealMatrix.IsPermutation;
  cfcn := _TComplexMatrix.IsPermutation;
end;

{ FCN_IsCirculant }

procedure FCN_IsCirculant.InitNode;
begin
  rfcn := _TRealMatrix.IsCirculant;
  cfcn := _TComplexMatrix.IsCirculant;
end;

{ FCN_IsToeplitz }

procedure FCN_IsToeplitz.InitNode;
begin
  rfcn := _TRealMatrix.IsToeplitz;
  cfcn := _TComplexMatrix.IsToeplitz;
end;

{ FCN_IsHankel }

procedure FCN_IsHankel.InitNode;
begin
  rfcn := _TRealMatrix.IsHankel;
  cfcn := _TComplexMatrix.IsHankel;
end;

{ FCN_IsUpperHessenberg }

procedure FCN_IsUpperHessenberg.InitNode;
begin
  rfcn := _TRealMatrix.IsUpperHessenberg;
  cfcn := _TComplexMatrix.IsUpperHessenberg;
end;

{ FCN_IsLowerHessenberg }

procedure FCN_IsLowerHessenberg.InitNode;
begin
  rfcn := _TRealMatrix.IsLowerHessenberg;
  cfcn := _TComplexMatrix.IsLowerHessenberg;
end;

{ FCN_IsTridiagonal }

procedure FCN_IsTridiagonal.InitNode;
begin
  rfcn := _TRealMatrix.IsTridiagonal;
  cfcn := _TComplexMatrix.IsTridiagonal;
end;

{ FCN_IsUpperBidiagonal }

procedure FCN_IsUpperBidiagonal.InitNode;
begin
  rfcn := _TRealMatrix.IsUpperBidiagonal;
  cfcn := _TComplexMatrix.IsUpperBidiagonal;
end;

{ FCN_IsLowerBidiagonal }

procedure FCN_IsLowerBidiagonal.InitNode;
begin
  rfcn := _TRealMatrix.IsLowerBidiagonal;
  cfcn := _TComplexMatrix.IsLowerBidiagonal;
end;

{ FCN_IsBidiagonal }

procedure FCN_IsBidiagonal.InitNode;
begin
  rfcn := _TRealMatrix.IsBidiagonal;
  cfcn := _TComplexMatrix.IsBidiagonal;
end;

{ FCN_IsCentrosymmetric }

procedure FCN_IsCentrosymmetric.InitNode;
begin
  rfcn := _TRealMatrix.IsCentrosymmetric;
  cfcn := _TComplexMatrix.IsCentrosymmetric;
end;

{ FCN_IsVandermonde }

procedure FCN_IsVandermonde.InitNode;
begin
  rfcn := _TRealMatrix.IsVandermonde;
  cfcn := _TComplexMatrix.IsVandermonde;
end;

{ FCN_IsIdempotent }

procedure FCN_IsIdempotent.InitNode;
begin
  rfcn := _TRealMatrix.IsIdempotent;
  cfcn := _TComplexMatrix.IsIdempotent;
end;

{ FCN_IsInvolution }

procedure FCN_IsInvolution.InitNode;
begin
  rfcn := _TRealMatrix.IsInvolution;
  cfcn := _TComplexMatrix.IsInvolution;
end;

{ FCN_IsPositiveDefinite }

procedure FCN_IsPositiveDefinite.InitNode;
begin
  rfcn := _TRealMatrix.IsPositiveDefinite;
  cfcn := _TComplexMatrix.IsPositiveDefinite;
end;

{ FCN_IsPositiveSemidefinite }

procedure FCN_IsPositiveSemidefinite.InitNode;
begin
  rfcn := _TRealMatrix.IsPositiveSemidefinite;
  cfcn := _TComplexMatrix.IsPositiveSemidefinite;
end;

{ FCN_IsNegativeDefinite }

procedure FCN_IsNegativeDefinite.InitNode;
begin
  rfcn := _TRealMatrix.IsNegativeDefinite;
  cfcn := _TComplexMatrix.IsNegativeDefinite;
end;

{ FCN_IsNegativeSemidefinite }

procedure FCN_IsNegativeSemidefinite.InitNode;
begin
  rfcn := _TRealMatrix.IsNegativeSemidefinite;
  cfcn := _TComplexMatrix.IsNegativeSemidefinite;
end;

{ FCN_IsIndefinite }

procedure FCN_IsIndefinite.InitNode;
begin
  rfcn := _TRealMatrix.IsIndefinite;
  cfcn := _TComplexMatrix.IsIndefinite;
end;

{ FCN_IsNilpotent }

procedure FCN_IsNilpotent.InitNode;
begin
  rfcn := _TRealMatrix.IsNilpotent;
  cfcn := _TComplexMatrix.IsNilpotent;
end;

{ TMatrixIntFcnWithEpsilon }

procedure TMatrixIntFcnWithEpsilon.DoExecute;
begin
  inherited;
  Result := ASOInt(generic_result);
end;

{ FCN_NilpotencyIndex }

procedure FCN_NilpotencyIndex.InitNode;
begin
  rfcn := _TRealMatrix.NilpotencyIndex;
  cfcn := _TComplexMatrix.NilpotencyIndex;
end;

{ TNumEntEpsilonFunction }

procedure TNumEntEpsilonFunction.DoExecute;
var
  Obj: TAlgosimNumericEntity;
  Eps: TASR;
begin

  CheckNumArgs([1, 2]);
  if not ExtractRef<TAlgosimNumericEntity>(0, Obj) then Exit;
  if not EvalChildren(1) then Exit;

  Args.Skip.ExtractNonNeg(Eps, 0).Close;

  fcn(Obj, Eps);

end;

{ FCN_IsPositive }

procedure FCN_IsPositive.fcn(AObj: TAlgosimNumericEntity; const AEps: TASR);
begin
  Result := ASO(AObj.IsPositive(AEps));
end;

{ FCN_IsNonNegative }

procedure FCN_IsNonNegative.fcn(AObj: TAlgosimNumericEntity;
  const AEps: TASR);
begin
  Result := ASO(AObj.IsNonNegative(AEps));
end;

{ FCN_IsNegative }

procedure FCN_IsNegative.fcn(AObj: TAlgosimNumericEntity; const AEps: TASR);
begin
  Result := ASO(AObj.IsNegative(AEps));
end;

{ FCN_IsNonPositive }

procedure FCN_IsNonPositive.fcn(AObj: TAlgosimNumericEntity;
  const AEps: TASR);
begin
  Result := ASO(AObj.IsNonPositive(AEps));
end;

{ FCN_IsZero }

procedure FCN_IsZero.fcn(AObj: TAlgosimNumericEntity; const AEps: TASR);
begin
  Result := ASO(AObj.IsZero(AEps));
end;

{ FCN_IsNonZero }

procedure FCN_IsNonZero.fcn(AObj: TAlgosimNumericEntity; const AEps: TASR);
begin
  Result := ASO(AObj.IsNonZero(AEps));
end;

{ FCN_PivotPos }

procedure FCN_PivotPos.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  N: Integer;
  Eps: TASR;
begin

  Args.Extract(Mat).ExtractPos(N).ExtractNonNeg(Eps, 0).Close;
  Dec(N);

  if Mat.IsComplex then
    Result := ASOInt(Mat.AsComplexMatrix.PivotPos(N, Eps) + 1)
  else
    Result := ASOInt(Mat.AsRealMatrix.PivotPos(N, Eps) + 1);

end;

{ FCN_IsZeroRow }

procedure FCN_IsZeroRow.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  N: Integer;
  Eps: TASR;
begin

  Args.Extract(Mat).ExtractPos(N).ExtractNonNeg(Eps, 0).Close;
  Dec(N);

  if Mat.IsComplex then
    Result := ASO(Mat.AsComplexMatrix.IsZeroRow(N, Eps))
  else
    Result := ASO(Mat.AsRealMatrix.IsZeroRow(N, Eps));

end;

{ FCN_IsEssentiallyZeroRow }

procedure FCN_IsEssentiallyZeroRow.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  N: Integer;
  Eps: TASR;
begin

  Args.Extract(Mat).ExtractPos(N).ExtractNonNeg(Eps, 0).Close;
  Dec(N);

  if Mat.IsComplex then
    Result := ASO(Mat.AsComplexMatrix.IsEssentiallyZeroRow(N, Eps))
  else
    Result := ASO(Mat.AsRealMatrix.IsEssentiallyZeroRow(N, Eps));

end;

{ FCN_IsDiagonallyDominant }

procedure FCN_IsDiagonallyDominant.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin

  Args.Extract(Mat).Close;

  if Mat.IsComplex then
    Result := ASO(Mat.AsComplexMatrix.IsDiagonallyDominant)
  else
    Result := ASO(Mat.AsRealMatrix.IsDiagonallyDominant);

end;

{ FCN_IsStrictlyDiagonallyDominant }

procedure FCN_IsStrictlyDiagonallyDominant.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin

  Args.Extract(Mat).Close;

  if Mat.IsComplex then
    Result := ASO(Mat.AsComplexMatrix.IsStrictlyDiagonallyDominant)
  else
    Result := ASO(Mat.AsRealMatrix.IsStrictlyDiagonallyDominant);

end;

{ FCN_CommutesWith }

procedure FCN_CommutesWith.SimpleFunction;
var
  Mat, Mat2: TAlgosimMatrix;
  Eps: TASR;
begin

  Args.Extract(Mat).Extract(Mat2).ExtractNonNeg(Eps, 0).Close;

  if HasComplexArg then
    Result := ASO(Commute(Mat.AsComplexMatrix, Mat2.AsComplexMatrix, Eps))
  else
    Result := ASO(Commute(Mat.AsRealMatrix, Mat2.AsRealMatrix, Eps));

end;

{ FCN_ToLowerTriangular }

procedure FCN_ToLowerTriangular.SimpleFunction;
var
  Mat: TAlgosimObject;
  RM: TRealMatrix;
  CM: TComplexMatrix;
begin

  Args.Extract(Mat).Close;

  if Mat.IsComplex then
  begin
    CM := Mat.AsComplexMatrix;
    CM.MakeLowerTriangular;
    Result := ASO(CM);
  end
  else
  begin
    RM := Mat.AsRealMatrix;
    RM.MakeLowerTriangular;
    Result := ASO(RM);
  end;

end;

{ FCN_ToUpperTriangular }

procedure FCN_ToUpperTriangular.SimpleFunction;
var
  Mat: TAlgosimObject;
  RM: TRealMatrix;
  CM: TComplexMatrix;
begin

  Args.Extract(Mat).Close;

  if Mat.IsComplex then
  begin
    CM := Mat.AsComplexMatrix;
    CM.MakeUpperTriangular;
    Result := ASO(CM);
  end
  else
  begin
    RM := Mat.AsRealMatrix;
    RM.MakeUpperTriangular;
    Result := ASO(RM);
  end;

end;

{ FCN_ToUpperHessenberg }

procedure FCN_ToUpperHessenberg.SimpleFunction;
var
  Mat: TAlgosimObject;
  RM: TRealMatrix;
  CM: TComplexMatrix;
begin

  Args.Extract(Mat).Close;

  if Mat.IsComplex then
  begin
    CM := Mat.AsComplexMatrix;
    CM.MakeUpperHessenberg;
    Result := ASO(CM);
  end
  else
  begin
    RM := Mat.AsRealMatrix;
    RM.MakeUpperHessenberg;
    Result := ASO(RM);
  end;

end;

{ FCN_HermitianSquare }

procedure FCN_HermitianSquare.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := Mat.HermitianSquare;
end;

{ FCN_Modulus }

procedure FCN_Modulus.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := Mat.Modulus;
end;

{ FCN_Determinant }

procedure FCN_Determinant.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := Mat.Determinant;
end;

{ FCN_Trace }

procedure FCN_Trace.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := Mat.Trace;
end;

{ FCN_Inverse }

procedure FCN_Inverse.SimpleFunction;
var
  Arg: TAlgosimNumericEntity;
begin
  Args.Extract(Arg).Close;
  Result := Arg.Inverse;
end;

{ FCN_Rank }

procedure FCN_Rank.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := ASOInt(Mat.Rank);
end;

{ FCN_Nullity }

procedure FCN_Nullity.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := ASOInt(Mat.Nullity);
end;

{ FCN_ConditionNumber }

procedure FCN_ConditionNumber.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  p: Integer;
begin
  if (Args.PeekAt(1) is TAlgosimRealNumber) and (Args.PeekAt(1).ToASR = Infinity) then
  begin
    Args.Extract(Mat).Skip.Close;
    Result := ASO(Mat.ConditionNumber(INFTY));
  end
  else
  begin
    Args.Extract(Mat).Extract(p, 2).Close;
    Result := ASO(Mat.ConditionNumber(p));
  end;
end;

{ FCN_IsSingular }

procedure FCN_IsSingular.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := ASO(Mat.IsSingular);
end;

{ FCN_DeletedAbsoluteRowSum }

procedure FCN_DeletedAbsoluteRowSum.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  N: Integer;
begin
  Args.Extract(Mat).ExtractPos(N).Close;
  Result := ASO(Mat.DeletedAbsoluteRowSum(N));
end;

{ FCN_RowSwap }

procedure FCN_RowSwap.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  N, N2: Integer;
begin

  Args.MoveObject<TAlgosimMatrix>(Value, Mat).ExtractPos(N).ExtractPos(N2).Close;

  if not InRange(N, 1, Mat.Dimension.Rows) then
    raise EAlgosimObjectException.CreateFmt(SIndexOutOfBounds, [N]);

  if not InRange(N2, 1, Mat.Dimension.Rows) then
    raise EAlgosimObjectException.CreateFmt(SIndexOutOfBounds, [N2]);

  if N = N2 then
    Exit;

  Dec(N);
  Dec(N2);

  if Result is TAlgosimRealMatrix then
    TAlgosimRealMatrix(Result).Value.RowSwap(N, N2)
  else if Result is TAlgosimComplexMatrix then
    TAlgosimComplexMatrix(Result).Value.RowSwap(N, N2)
  else
    ErrInternal;

end;

{ FCN_RowScale }

procedure FCN_RowScale.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  N: Integer;
  Factor: TASR;
begin

  Args.MoveObject<TAlgosimMatrix>(Value, Mat)
    .ExtractPos(N).Extract(Factor).Close;

  if not InRange(N, 1, Mat.Dimension.Rows) then
    raise EAlgosimObjectException.CreateFmt(SIndexOutOfBounds, [N]);

  if Factor = 1 then
    Exit;

  Dec(N);

  if Result is TAlgosimRealMatrix then
    TAlgosimRealMatrix(Result).Value.RowScale(N, Factor)
  else if Result is TAlgosimComplexMatrix then
    TAlgosimComplexMatrix(Result).Value.RowScale(N, Factor)
  else
    ErrInternal;

end;

{ FCN_RowAddMul }

procedure FCN_RowAddMul.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  N, N2: Integer;
  Factor: TASR;
begin

  Args.MoveObject<TAlgosimMatrix>(Value, Mat)
    .ExtractPos(N).ExtractPos(N2).Extract(Factor).Close;

  if not InRange(N, 1, Mat.Dimension.Rows) then
    raise EAlgosimObjectException.CreateFmt(SIndexOutOfBounds, [N]);

  if not InRange(N2, 1, Mat.Dimension.Rows) then
    raise EAlgosimObjectException.CreateFmt(SIndexOutOfBounds, [N2]);

  Dec(N);
  Dec(N2);

  if Factor = 0 then
    Exit;

  if Result is TAlgosimRealMatrix then
    TAlgosimRealMatrix(Result).Value.RowAddMul(N, N2, Factor)
  else if Result is TAlgosimComplexMatrix then
    TAlgosimComplexMatrix(Result).Value.RowAddMul(N, N2, Factor)
  else
    ErrInternal;

end;

{ FCN_RowEchelonForm }

procedure FCN_RowEchelonForm.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := Mat.RowEchelonForm;
end;

{ FCN_ReducedRowEchelonForm }

procedure FCN_ReducedRowEchelonForm.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := Mat.ReducedRowEchelonForm;
end;

{ FCN_NumZeroRows }

procedure FCN_NumZeroRows.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Eps: TASR;
begin
  Args.Extract(Mat).ExtractNonNeg(Eps, 0).Close;
  Result := ASOInt(Mat.NumZeroRows(Eps));
end;

{ FCN_NumTrailingZeroRows }

procedure FCN_NumTrailingZeroRows.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Eps: TASR;
begin
  Args.Extract(Mat).ExtractNonNeg(Eps, 0).Close;
  Result := ASOInt(Mat.NumTrailingZeroRows(Eps));
end;

{ FCN_GramSchmidt }

procedure FCN_GramSchmidt.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := Mat.GramSchmidt;
end;

{ FCN_ColumnSpaceBasis }

procedure FCN_ColumnSpaceBasis.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := Mat.ColumnSpaceBasis;
end;

{ FCN_ColumnSpaceProjection }

procedure FCN_ColumnSpaceProjection.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Vect: TAlgosimVector;
begin

  Args.Extract(Mat).Extract(Vect).Close;

  if HasComplexArg then
    Result := ASO(Mat.AsComplexMatrix.ColumnSpaceProjection(Vect.AsComplexVector))
  else
    Result := ASO(Mat.AsRealMatrix.ColumnSpaceProjection(Vect.AsRealVector));

end;

{ FCN_DistanceFromColumnSpace }

procedure FCN_DistanceFromColumnSpace.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Vect: TAlgosimVector;
begin

  Args.Extract(Mat).Extract(Vect).Close;

  if HasComplexArg then
    Result := ASO(Mat.AsComplexMatrix.DistanceFromColumnSpace(Vect.AsComplexVector))
  else
    Result := ASO(Mat.AsRealMatrix.DistanceFromColumnSpace(Vect.AsRealVector));

end;

{ FCN_Eigenvalues }

procedure FCN_Eigenvalues.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Eigenvalues: TComplexVector;
begin
  Args.Extract(Mat).Close;
  Eigenvalues := Mat.Eigenvalues;
  if Eigenvalues.IsReal then
    Result := ASO(Eigenvalues.RealPart)
  else
    Result := ASO(Eigenvalues);
end;

{ FCN_Spectrum }

procedure FCN_Spectrum.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Eigenvalues: TComplexVector;
  x: TASR;
  z: TASC;
begin
  Args.Extract(Mat).Close;
  Eigenvalues := Mat.Eigenvalues;
  Result := TAlgosimSet.Create;
  if Eigenvalues.IsReal then
    for x in Eigenvalues.RealPart.Data do
      Result.AddElement(ASO(x))
  else
    for z in Eigenvalues.Data do
      Result.AddElement(ASO(z))
end;

{ FCN_Eigenvectors }

procedure FCN_Eigenvectors.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := Mat.Eigenvectors;
end;

{ FCN_IsEigenvector }

procedure FCN_IsEigenvector.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Vect: TAlgosimVector;
  Eps: TASR;
begin

  Args.Extract(Mat).Extract(Vect).ExtractNonNeg(Eps, 1E-12).Close;

  if HasComplexArg then
    Result := ASO(Mat.AsComplexMatrix.IsEigenvector(Vect.AsComplexVector, Eps))
  else
    Result := ASO(Mat.AsRealMatrix.IsEigenvector(Vect.AsRealVector, Eps));

end;

{ FCN_EigenvalueOf }

procedure FCN_EigenvalueOf.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Vect: TAlgosimVector;
  Eps: TASR;
begin

  Args.Extract(Mat).Extract(Vect).ExtractNonNeg(Eps, 1E-12).Close;

  if HasComplexArg then
    Result := ASO(Mat.AsComplexMatrix.EigenvalueOf(Vect.AsComplexVector, Eps))
  else
    Result := ASO(Mat.AsRealMatrix.EigenvalueOf(Vect.AsRealVector, Eps));

end;

{ FCN_IsEigenpair }

procedure FCN_IsEigenpair.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Vect: TAlgosimVector;
  Num: TAlgosimNumber;
  Eps: TASR;
begin

  Args.Extract(Mat).Extract(Vect).Extract(Num).ExtractNonNeg(Eps, 1E-12).Close;

  if HasComplexArg then
    Result := ASO(Mat.AsComplexMatrix.IsEigenpair(
      Num.ToASC,
      Vect.AsComplexVector,
      Eps
    ))
  else
    Result := ASO(Mat.AsRealMatrix.IsEigenpair(
      Num.ToASR,
      Vect.AsRealVector,
      Eps
    ));

end;

{ FCN_EigenvectorOf }

procedure FCN_EigenvectorOf.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Num: TAlgosimNumber;
begin

  Args.Extract(Mat).Extract(Num).Close;

  if HasComplexArg then
    Result := ASO(Mat.AsComplexMatrix.EigenvectorOf(Num.ToASC))
  else
    Result := ASO(Mat.AsRealMatrix.EigenvectorOf(Num.ToASR));

end;

{ FCN_SpectralRadius }

procedure FCN_SpectralRadius.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := ASO(Mat.SpectralRadius);
end;

{ FCN_SingularValues }

procedure FCN_SingularValues.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := ASO(Mat.SingularValues);
end;

{ FCN_Defuzz }

procedure FCN_Defuzz.SimpleFunction;
var
  Obj: TAlgosimNumericEntity;
  Eps: TASR;
begin
  Args.MoveObject<TAlgosimNumericEntity>(Value, Obj).ExtractPos(Eps, 1E-8).Close;
  Obj.Defuzz(Eps);
end;

{ FCN_Vectorization }

procedure FCN_Vectorization.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := Mat.Vectorization;
end;

{ FCN_Aug }

procedure FCN_Aug.SimpleFunction;
var
  Mat: TAlgosimNumericArray;
  AugObj: TAlgosimNumericEntity;
begin
  Args.Extract(Mat).Extract(AugObj).Close;
  if HasComplexArg then
    Result := ASO(Mat.AsComplexMatrix.Augment(AugObj.AsComplexMatrix))
  else
    Result := ASO(Mat.AsRealMatrix.Augment(AugObj.AsRealMatrix));
end;

{ FCN_SubmatrixByRemoval }

procedure FCN_SubmatrixByRemoval.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Row, Col: Integer;
begin

  Args.Extract(Mat).ExtractPos(Row).ExtractPos(Col).Close;
  Dec(Row);
  Dec(Col);

  if Mat.IsComplex then
    Result := ASO(Mat.AsComplexMatrix.Submatrix(Row, Col))
  else
    Result := ASO(Mat.AsRealMatrix.Submatrix(Row, Col));

end;

{ FCN_LeadingPrincipalSubmatrix }

procedure FCN_LeadingPrincipalSubmatrix.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  N: Integer;
begin

  Args.Extract(Mat).ExtractPos(N).Close;

  if Mat.IsComplex then
    Result := ASO(Mat.AsComplexMatrix.LeadingPrincipalSubmatrix(N))
  else
    Result := ASO(Mat.AsRealMatrix.LeadingPrincipalSubmatrix(N));

end;

{ FCN_Lessen }

procedure FCN_Lessen.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin

  Args.Extract(Mat).Close;

  if Mat.IsComplex then
    Result := ASO(Mat.AsComplexMatrix.Lessened)
  else
    Result := ASO(Mat.AsRealMatrix.Lessened);

end;

{ FCN_Minor }

procedure FCN_Minor.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Row, Col: Integer;
begin
  Args.Extract(Mat).ExtractPos(Row).ExtractPos(Col).Close;
  Result := Mat.Minor(Row, Col);
end;

{ FCN_Cofactor }

procedure FCN_Cofactor.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Row, Col: Integer;
begin
  Args.Extract(Mat).ExtractPos(Row).ExtractPos(Col).Close;
  Result := Mat.Cofactor(Row, Col);
end;

{ FCN_CofactorMatrix }

procedure FCN_CofactorMatrix.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := Mat.CofactorMatrix;
end;

{ FCN_AdjugateMatrix }

procedure FCN_AdjugateMatrix.SimpleFunction;
var
  Mat: TAlgosimMatrix;
begin
  Args.Extract(Mat).Close;
  Result := Mat.AdjugateMatrix;
end;

{ FCN_LU }

procedure FCN_LU.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  ListLength: Integer;
  P, L, U: TRealMatrix;
  cP, cL, cU: TComplexMatrix;
begin

  Args.Extract(Mat).Close;

  if not TryGetAssignmentListLength(ListLength) then
    ListLength := 3;

  if Mat.IsComplex then
  begin
    Mat.AsComplexMatrix.LU(cP, cL, cU);
    if ListLength = 2 then
      Result := TAlgosimAssignmentList.CreateWithValue([ASO(cL), ASO(cU)])
    else
      Result := TAlgosimAssignmentList.CreateWithValue([ASO(cP), ASO(cL), ASO(cU)]);
  end
  else
  begin
    Mat.AsRealMatrix.LU(P, L, U);
    if ListLength = 2 then
      Result := TAlgosimAssignmentList.CreateWithValue([ASO(L), ASO(U)])
    else
      Result := TAlgosimAssignmentList.CreateWithValue([ASO(P), ASO(L), ASO(U)]);
  end;

end;

{ FCN_Cholesky }

procedure FCN_Cholesky.SimpleFunction;
resourcestring
  SCouldntComputeCholesky = 'Couldn''t compute Cholesky factor.';
var
  Mat: TAlgosimMatrix;
  R: TRealMatrix;
  cR: TComplexMatrix;
begin

  Args.Extract(Mat).Close;

  if Mat.IsComplex and Mat.AsComplexMatrix.Cholesky(cR) then
    Result := ASO(cR)
  else if not Mat.IsComplex and Mat.AsRealMatrix.Cholesky(R) then
    Result := ASO(R)
  else
    Result := ASO(failure, SCouldntComputeCholesky)

end;

{ FCN_QR }

procedure FCN_QR.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Q, R: TRealMatrix;
  cQ, cR: TComplexMatrix;
begin

  Args.Extract(Mat).Close;

  if Mat.IsComplex then
  begin
    Mat.AsComplexMatrix.QR(cQ, cR);
    Result := TAlgosimAssignmentList.CreateWithValue([ASO(cQ), ASO(cR)])
  end
  else
  begin
    Mat.AsRealMatrix.QR(Q, R);
    Result := TAlgosimAssignmentList.CreateWithValue([ASO(Q), ASO(R)])
  end;

end;

{ FCN_Hessenberg }

procedure FCN_Hessenberg.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  A, U: TRealMatrix;
  cA, cU: TComplexMatrix;
begin

  Args.Extract(Mat).Close;

  if Mat.IsComplex then
  begin
    Mat.AsComplexMatrix.Hessenberg(cA, cU);
    Result := TAlgosimAssignmentList.CreateWithValue([ASO(cA), ASO(cU)])
  end
  else
  begin
    mat.AsRealMatrix.Hessenberg(A, U);
    Result := TAlgosimAssignmentList.CreateWithValue([ASO(A), ASO(U)])
  end;

end;

{ FCN_SameValue }

procedure FCN_SameValue.SimpleFunction;
var
  Arg1, Arg2: TAlgosimObject;
  Eps: TASR;
begin
  Args.Extract(Arg1).Extract(Arg2).ExtractNonNeg(Eps, 0).Close;
  Result := ASO(SameASO(Arg1, Arg2, Eps));
end;

{ FCN_CompareValue }

procedure FCN_CompareValue.SimpleFunction;
var
  Arg1, Arg2: TAlgosimObject;
begin
  Args.Extract(Arg1).Extract(Arg2).Close;
  Result := ASOInt(CompareASO(Arg1, Arg2));
end;

{ FCN_ZeroMatrix }

procedure FCN_ZeroMatrix.SimpleFunction;
var
  N, M: Integer;
begin
  Args.ExtractPos(N).ExtractPos(M, N).Close;
  Result := ASO(ZeroMatrix(TMatrixSize.Create(N, M)));
end;

{ FCN_ComplexZeroMatrix }

procedure FCN_ComplexZeroMatrix.SimpleFunction;
var
  N, M: Integer;
begin
  Args.ExtractPos(N).ExtractPos(M, N).Close;
  Result := ASO(ComplexZeroMatrix(TMatrixSize.Create(N, M)));
end;

{ FCN_IdentityMatrix }

procedure FCN_IdentityMatrix.SimpleFunction;
var
  N: Integer;
begin
  Args.ExtractPos(N).Close;
  Result := ASO(IdentityMatrix(N));
end;

{ FCN_ReversalMatrix }

procedure FCN_ReversalMatrix.SimpleFunction;
var
  N: Integer;
begin
  Args.ExtractPos(N).Close;
  Result := ASO(ReversalMatrix(N));
end;

{ FCN_RandomMatrix }

procedure FCN_RandomMatrix.SimpleFunction;
var
  N, M: Integer;
begin
  Args.ExtractPos(N).ExtractPos(M, N).Close;
  Result := ASO(RandomMatrix(TMatrixSize.Create(N, M)));
end;

{ FCN_RandomIntMatrix }

procedure FCN_RandomIntMatrix.SimpleFunction;
var
  N, M, A, B: Integer;
begin

  CheckNumArgs([3, 4]);

  case ChildCount of
    3:
      begin
        Args.ExtractPos(N).Extract(A).Extract(B).Close;
        if A >= B then
          raise EInvArgs.Create('The set of possible values is empty.');
        Result := ASO(RandomIntMatrix(N, A, B));
      end;
    4:
      begin
        Args.ExtractPos(N).ExtractPos(M).Extract(A).Extract(B).Close;
        if A >= B then
          raise EInvArgs.Create('The set of possible values is empty.');
        Result := ASO(RandomIntMatrix(TMatrixSize.Create(N, M), A, B));
      end
  else
    ErrInvalidArguments;
  end;

end;

{ FCN_OuterProduct }

procedure FCN_OuterProduct.SimpleFunction;
var
  Vect1, Vect2: TAlgosimVector;
begin

  Args.Extract(Vect1).Extract(Vect2).Close;

  if HasComplexArg then
    Result := ASO(OuterProduct(Vect1.AsComplexVector, Vect2.AsComplexVector))
  else
    Result := ASO(OuterProduct(Vect1.AsRealVector, Vect2.AsRealVector));

end;

{ FCN_CirculantMatrix }

procedure FCN_CirculantMatrix.SimpleFunction;
var
  Vect: TAlgosimVector;
begin

  Args.Extract(Vect).Close;

  if Vect.IsComplex then
    Result := ASO(CirculantMatrix(Vect.AsComplexVector.Data))
  else
    Result := ASO(CirculantMatrix(Vect.AsRealVector.Data));

end;

{ FCN_ToeplitzMatrix }

procedure FCN_ToeplitzMatrix.SimpleFunction;
var
  Vect1, Vect2: TAlgosimVector;
begin

  Args.Extract(Vect1).Extract(Vect2).Close;

  if HasComplexArg then
    Result := ASO(ToeplitzMatrix(Vect1.AsComplexVector.Data, Vect2.AsComplexVector.Data))
  else
    Result := ASO(ToeplitzMatrix(Vect1.AsRealVector.Data, Vect2.AsRealVector.Data));

end;

{ FCN_HankelMatrix }

procedure FCN_HankelMatrix.SimpleFunction;
var
  Vect1, Vect2: TAlgosimVector;
begin

  Args.Extract(Vect1).Extract(Vect2).Close;

  if HasComplexArg then
    Result := ASO(HankelMatrix(Vect1.AsComplexVector.Data, Vect2.AsComplexVector.Data))
  else
    Result := ASO(HankelMatrix(Vect1.AsRealVector.Data, Vect2.AsRealVector.Data));

end;

{ FCN_BackwardShiftMatrix }

procedure FCN_BackwardShiftMatrix.SimpleFunction;
var
  N: Integer;
begin
  Args.ExtractPos(N).Close;
  Result := ASO(BackwardShiftMatrix(N));
end;

{ FCN_ForwardShiftMatrix }

procedure FCN_ForwardShiftMatrix.SimpleFunction;
var
  N: Integer;
begin
  Args.ExtractPos(N).Close;
  Result := ASO(ForwardShiftMatrix(N));
end;

{ FCN_VandermondeMatrix }

procedure FCN_VandermondeMatrix.SimpleFunction;
var
  Vect: TAlgosimVector;
  N: Integer;
begin

  Args.Extract(Vect).ExtractNonNeg(N, 0).Close;

  if Vect.IsComplex then
    Result := ASO(VandermondeMatrix(Vect.AsComplexVector.Data, N))
  else
    Result := ASO(VandermondeMatrix(Vect.AsRealVector.Data, N));

end;

{ FCN_HilbertMatrix }

procedure FCN_HilbertMatrix.SimpleFunction;
var
  N, M: Integer;
begin
  Args.ExtractPos(N).ExtractPos(M, N).Close;
  Result := ASO(HilbertMatrix(TMatrixSize.Create(N, M)));
end;

{ FCN_RotationMatrix }

procedure FCN_RotationMatrix.SimpleFunction;
var
  Theta: TASR;
  Direction: TRealVector;
  N, I, J: Integer;
begin
  if Args.PeekAt(1) is TAlgosimVector then
  begin
    Args
      .Extract(Theta)
      .Extract(Direction)
      .Close;
    Result := ASO(RotationMatrix(Theta, Direction));
  end
  else
  begin
    Args
      .Extract(Theta)
      .ExtractPos(N, 2)
      .ExtractPos(I, 1)
      .ExtractPos(J, 2)
      .Close;
    Dec(I);
    Dec(J);
    Result := ASO(RotationMatrix(Theta, N, I, J));
  end;
end;

{ FCN_ReflectionMatrix }

procedure FCN_ReflectionMatrix.SimpleFunction;
var
  Vect: TAlgosimVector;
begin

  Args.Extract(Vect).Close;

  if Vect.IsComplex then
    Result := ASO(ReflectionMatrix(Vect.AsComplexVector))
  else
    Result := ASO(ReflectionMatrix(Vect.AsRealVector));

end;

{ FCN_HadamardProduct }

procedure FCN_HadamardProduct.SimpleFunction;
var
  Mat1, Mat2: TAlgosimMatrix;
begin

  Args.Extract(Mat1).Extract(Mat2).Close;

  if HasComplexArg then
    Result := ASO(HadamardProduct(Mat1.AsComplexMatrix, Mat2.AsComplexMatrix))
  else
    Result := ASO(HadamardProduct(Mat1.AsRealMatrix, Mat2.AsRealMatrix));

end;

{ FCN_DirectSum }

procedure FCN_DirectSum.SimpleFunction;
var
  Args: TArgumentExtractor;
  Mats: TArray<TAlgosimMatrix>;
  Rmats: TArray<TRealMatrix>;
  Cmats: TArray<TComplexMatrix>;
  HasCplx: Boolean;
  i: Integer;
begin

  Args := Self.Args;
  SetLength(Mats, Args.Count);
  i := 0;
  HasCplx := False;
  while Args.ArgExists do
  begin
    Args := Args.Extract(Mats[i]);
    if Mats[i].IsComplex then
      HasCplx := True;
    Inc(i);
  end;

  if HasCplx then
  begin
    SetLength(Cmats, Length(Mats));
    for i := 0 to High(Mats) do
      Cmats[i] := Mats[i].AsComplexMatrix;
    Result := ASO(DirectSum(Cmats));
  end
  else
  begin
    SetLength(Rmats, Length(Mats));
    for i := 0 to High(Mats) do
      Rmats[i] := Mats[i].AsRealMatrix;
    Result := ASO(DirectSum(Rmats));
  end;

end;

{ FCN_ForwardSubstitution }

procedure FCN_ForwardSubstitution.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Vect: TAlgosimVector;
begin

  Args.Extract(Mat).Extract(Vect).Close;

  if HasComplexArg then
    Result := ASO(ForwardSubstitution(Mat.AsComplexMatrix, Vect.AsComplexVector))
  else
    Result := ASO(ForwardSubstitution(Mat.AsRealMatrix, Vect.AsRealVector));

end;

{ FCN_BackSubstitution }

procedure FCN_BackSubstitution.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  Vect: TAlgosimVector;
begin

  Args.Extract(Mat).Extract(Vect).Close;

  if HasComplexArg then
    Result := ASO(BackSubstitution(Mat.AsComplexMatrix, Vect.AsComplexVector))
  else
    Result := ASO(BackSubstitution(Mat.AsRealMatrix, Vect.AsRealVector));

end;

{ FCN_SysSolve }

procedure FCN_SysSolve.SimpleFunction;
var
  Mat: TAlgosimMatrix;
  RHS: TAlgosimNumericArray;
begin

  Args.Extract(Mat);

  if Args.Count = 1 then
  begin
    if HasComplexArg then
      Result := ASO(SysSolve(Mat.AsComplexMatrix))
    else
      Result := ASO(SysSolve(Mat.AsRealMatrix));
  end
  else
  begin
    Args.Skip.Extract(RHS).Close;
    if RHS is TAlgosimVector then
      if HasComplexArg then
        Result := ASO(SysSolve(Mat.AsComplexMatrix, RHS.AsComplexVector))
      else
        Result := ASO(SysSolve(Mat.AsRealMatrix, RHS.AsRealVector))
    else
      if HasComplexArg then
        Result := ASO(SysSolve(Mat.AsComplexMatrix, RHS.AsComplexMatrix))
      else
        Result := ASO(SysSolve(Mat.AsRealMatrix, RHS.AsRealMatrix));
  end;

end;

{ FCN_LeastSquaresPolynomialFit }

procedure FCN_LeastSquaresPolynomialFit.SimpleFunction;
var
  X, Y: TAlgosimVector;
  N: Integer;
begin

  Args.Extract(X).Extract(Y).ExtractNonNeg(N).Close;

  if HasComplexArg then
    Result := ASO(LeastSquaresPolynomialFit(X.AsComplexVector, Y.AsComplexVector, N))
  else
    Result := ASO(LeastSquaresPolynomialFit(X.AsRealVector, Y.AsRealVector, N));

end;

{ FCN_AreParallel }

procedure FCN_AreParallel.SimpleFunction;
var
  Vect1, Vect2: TAlgosimVector;
  Eps: TASR;
begin

  Args.Extract(Vect1).Extract(Vect2).ExtractNonNeg(Eps, 0).Close;

  if HasComplexArg then
    Result := ASO(AreParallel(Vect1.AsComplexVector, Vect2.AsComplexVector, Eps))
  else
    Result := ASO(AreParallel(Vect1.AsRealVector, Vect2.AsRealVector, Eps));

end;

{ FCN_AreNotParallel }

procedure FCN_AreNotParallel.SimpleFunction;
var
  Vect1, Vect2: TAlgosimVector;
  Eps: TASR;
begin

  Args.Extract(Vect1).Extract(Vect2).ExtractNonNeg(Eps, 0).Close;

  if HasComplexArg then
    Result := ASO(not AreParallel(Vect1.AsComplexVector, Vect2.AsComplexVector, Eps))
  else
    Result := ASO(not AreParallel(Vect1.AsRealVector, Vect2.AsRealVector, Eps));

end;

{ FCN_ArePerpendicular }

procedure FCN_ArePerpendicular.SimpleFunction;
var
  A, B: TASI;
  Vect1, Vect2: TAlgosimVector;
  Eps: TASR;
begin

  if Args.PeekAt(0) is TAlgosimNumber then
  begin
    Args.Extract(A).Extract(B).Close;
    Result := ASO(ASNum.coprime(A, B));
  end
  else
  begin

    Args.Extract(Vect1).Extract(Vect2).ExtractNonNeg(Eps, 0).Close;

    if HasComplexArg then
      Result := ASO(ArePerpendicular(Vect1.AsComplexVector, Vect2.AsComplexVector, Eps))
    else
      Result := ASO(ArePerpendicular(Vect1.AsRealVector, Vect2.AsRealVector, Eps));

  end;

end;

{ FCN_RGBValues }

procedure FCN_RGBValues.SimpleFunction;
var
  Color: TRGB;
begin
  Args.Extract(Color).Close;
  Result := ASORGB(Color);
end;

{ FCN_HSVValues }

procedure FCN_HSVValues.SimpleFunction;
var
  Color: TRGB;
begin
  Args.Extract(Color).Close;
  Result := ASOHSV(THSV(Color));
end;

{ FCN_HSLValues }

procedure FCN_HSLValues.SimpleFunction;
var
  Color: TRGB;
begin
  Args.Extract(Color).Close;
  Result := ASOHSL(THSL(Color));
end;

{ FCN_Color }

procedure FCN_Color.SimpleFunction;
var
  Arg: TAlgosimObject;
begin

  Args.Extract(Arg).Close;

  if Arg is TAlgosimColor then
    Args.MoveObject(Value)
  else
    Result := ASO(Arg.ToColor);

end;

{ FCN_HexColorCode }

procedure FCN_HexColorCode.SimpleFunction;
var
  Color: TAlgosimColor;
begin
  Args.Extract(Color).Close;
  Result := ASO(ColorToHex(Color.Value));
end;

{ FCN_GetNamedColors }

procedure FCN_GetNamedColors.SimpleFunction;
var
  i: Integer;
begin
  Args.Close;
  Result := TAlgosimArray.Create;
  Result.Capacity := Length(NamedColors);
  for i := 0 to High(NamedColors) do
    Result.AddElement(ASONamedColor(NamedColors[i].Name, NamedColors[i].Value));
end;

{ FCN_IsDark }

procedure FCN_IsDark.SimpleFunction;
var
  Color: TRGB;
begin
  Args.Extract(Color).Close;
  Result := ASO(ColorIsDark(Color));
end;

{ FCN_RGB }

procedure FCN_RGB.SimpleFunction;
var
  R, G, B: TASR;
begin
  Args.Extract(R).Extract(G).Extract(B).Close;
  Result := TAlgosimColor.CreateWithValue(
    TRGB.Create(
      R, G, B
    )
  );
end;

{ FCN_HSV }

procedure FCN_HSV.SimpleFunction;
var
  H, S, V: TASR;
begin
  Args.Extract(H).Extract(S).Extract(V).Close;
  Result := TAlgosimColor.CreateWithValue(
    TRGB(
      THSV.Create(
        H, S, V
      )
    )
  );
end;

{ FCN_HSL }

procedure FCN_HSL.SimpleFunction;
var
  H, S, L: TASR;
begin
  Args.Extract(H).Extract(S).Extract(L).Close;
  Result := TAlgosimColor.CreateWithValue(
    TRGB(
      THSL.Create(
        H, S, L
      )
    )
  );
end;

{ FCN_AddMember }

procedure FCN_AddMember.SimpleFunction;
var
  Struct: TAlgosimStructure;
  Name: string;
  NewValue: TAlgosimObject;
begin

  NewValue := nil;
  try
    Args
      .MoveObject<TAlgosimStructure>(Value, Struct)
      .Extract(Name)
      .MoveObject<TAlgosimObject>(NewValue)
      .Close;
  except
    FreeAndNil(NewValue);
    raise;
  end;

  Struct.Add(Name, NewValue);

end;

{ FCN_RemoveMember }

procedure FCN_RemoveMember.SimpleFunction;
var
  Struct: TAlgosimStructure;
  NameOrIndex: TAlgosimObject;
begin

  Args.MoveObject<TAlgosimStructure>(Value, Struct).Extract(NameOrIndex).Close;

  if NameOrIndex is TAlgosimString then
    Struct.Delete(NameOrIndex.ToString)
  else if NameOrIndex is TAlgosimNumber then
    Struct.Delete(NameOrIndex.ToInt32)
  else
    ErrInvalidArguments;

end;

{ FCN_SetValue }

procedure FCN_SetValue.SimpleFunction;
var
  Struct: TAlgosimStructure;
  NameOrIndex: TAlgosimObject;
  Value: TAlgosimObject;
  Index: Integer;
  Name: string;
  OwnsValue: Boolean;
begin

  OwnsValue := True;
  Value := nil;
  try

    Args
      .MoveObject<TAlgosimStructure>(Self.Value, Struct)
      .Extract(NameOrIndex)
      .MoveObject<TAlgosimObject>(Value)
      .Close;

    if NameOrIndex is TAlgosimString then
    begin
      Name := NameOrIndex.ToString;
      OwnsValue := False;
      Struct.Values[Name] := Value;
    end
    else if NameOrIndex is TAlgosimNumber then
    begin
      Index := NameOrIndex.ToInt32;
      OwnsValue := False;
      Struct.Values[Index] := Value;
    end
    else
      ErrInvalidArguments;

  finally
    if OwnsValue then
      Value.Free;
  end;

end;

{ FCN_RenameMember }

procedure FCN_RenameMember.SimpleFunction;
var
  Struct: TAlgosimStructure;
  OldName, NewName: string;
begin

  Args
    .MoveObject<TAlgosimStructure>(Value, Struct)
    .Extract(OldName)
    .Extract(NewName)
    .Close;

  Struct.RenameMember(OldName, NewName);

end;

{ FCN_HasMember }

procedure FCN_HasMember.DoExecute;
var
  Arg: TAlgosimStructure;
  Name: string;
begin
  CheckNumArgs(2);
  if not ExtractRef<TAlgosimStructure>(0, Arg) then Exit;
  if not EvalChild(1) then Exit;
  Args.Skip.Extract(Name).Close;
  Result := ASO(Arg.HasMember(Name));
end;

{ FCN_IndexOfName }

procedure FCN_IndexOfName.DoExecute;
var
  Arg: TAlgosimStructure;
  Name: string;
begin
  CheckNumArgs(2);
  if not ExtractRef<TAlgosimStructure>(0, Arg) then Exit;
  if not EvalChild(1) then Exit;
  Args.Skip.Extract(Name).Close;
  Result := ASOInt(Arg.IndexOfName(Name));
end;

{ FCN_ToStructType }

procedure FCN_ToStructType.SimpleFunction;
var
  Struct: TAlgosimStructure;
  Name: string;
begin
  Args.Extract(Struct).Extract(Name).Close;
  Result := Struct.ToStructType(Name);
end;

{ FCN_New }

procedure FCN_New.SimpleFunction;
var
  StructType: TAlgosimStructureType;
  i: Integer;
  Member: TAlgosimTypedStructure;
  Members: TArray<TAlgosimStructure.TMemberRef>;
  Args: TArgumentExtractor;
begin

  Args := Self.Args.Extract(StructType);

  SetLength(Members, Args.Count - 1);

  try
    for i := 1 to Args.Count - 1 do
    begin
      Args := Args.Extract(Member);
      if not stStructMember.MatchingName(Member) then
        ErrInvalidArguments;
      Members[i - 1].Name := Member['name'].ToString;
      Members[i - 1].Value := Member['value'];
      Member.Release('value');
    end;
  except
    for i := 0 to High(Members) do
      Members[i].Value.Free;
    raise;
  end;

  Result := StructType.New(Members);

end;

{ FCN_StructType }

procedure FCN_StructType.SimpleFunction;
var
  Name: string;
begin
  Args.Extract(Name).Close;
  Result := CreateStructTypeByName(Name);
end;

{ FCN_RegisterStructType }

procedure FCN_RegisterStructType.SimpleFunction;
var
  ST: TAlgosimStructureType;
begin
  Args.Extract(ST).Close;
  RegisterStructType(ST);
  Result := ASO(success);
end;

{ FCN_UnregisterStructType }

procedure FCN_UnregisterStructType.SimpleFunction;
var
  Name: string;
begin
  Args.Extract(Name).Close;
  UnregisterStructType(Name);
  Result := ASO(success);
end;

{ FCN_ValidateStruct }

procedure FCN_ValidateStruct.SimpleFunction;
var
  Struct: TAlgosimStructure;
  Name: string;
  StructType: TAlgosimStructureType;
begin

  Args.Extract(Struct).Extract(Name).Close;

  StructType := CreateStructTypeByName(Name);
  try
    Result := ASO(Struct.ValidateAgainst(StructType));
  finally
    StructType.Free;
  end;

end;

{ FCN_CreatePixmap }

procedure FCN_CreatePixmap.SimpleFunction;
var
  Width, Height: Integer;
  Color, BkColor: TRGB;
begin

  Args
    .ExtractPos(Width)
    .ExtractPos(Height)
    .Extract(Color, clWhite)
    .Extract(BkColor, clWhite)
    .Close;

  Result := ASO(TASPixmap.Create(Width, Height, Color, BkColor));

end;

{ FCN_AddBorder }

procedure FCN_AddBorder.SimpleFunction;
var
  Pixmap: TASPixmap;
  Width, Height: Integer;
  Color: TRGB;
begin

  Args
    .Extract(Pixmap)
    .Extract(Color)
    .ExtractNonNeg(Width)
    .ExtractNonNeg(Height, Width)
    .Close;

  Result := ASO(Pixmap.CloneWithBorder(Width, Height, Color));

end;

{ FCN_ExtendBorder }

procedure FCN_ExtendBorder.SimpleFunction;
var
  Pixmap: TASPixmap;
  Width, Height: Integer;
begin

  Args
    .Extract(Pixmap)
    .ExtractNonNeg(Width)
    .ExtractNonNeg(Height, Width)
    .Close;

  Result := ASO(Pixmap.CloneWithBorderExtension(Width, Height));

end;

{ FCN_ColorFrequencies }

procedure FCN_ColorFrequencies.SimpleFunction;
var
  Pixmap: TASPixmap;
  Data: TArray<TPair<TColor, Integer>>;
  i: Integer;
begin


  Args.Extract(Pixmap).Close;

  with Pixmap.CreateColorFreqDict do
    try
      Data := ToArray;
    finally
      Free;
    end;

  TArray.Sort<TPair<TColor, Integer>>(
    Data,
    TComparer<TPair<TColor, Integer>>.Construct(
      function(const ALeft, ARight: TPair<TColor, Integer>): Integer
      begin
        Result := CompareValue(ARight.Value, ALeft.Value); // descending order
      end
    )
  );

  Result := TAlgosimArray.Create;

  Result.Capacity := Length(Data);
  for i := 0 to High(Data) do
    Result.AddElement(
      ASO([
        TAlgosimColor.CreateWithValue(Data[i].Key),
        ASOInt(Data[i].Value)
      ])
    );

end;

{ FCN_ColorCount }

procedure FCN_ColorCount.SimpleFunction;
var
  Pixmap: TASPixmap;
begin
  Args.Extract(Pixmap).Close;
  Result := ASOInt(Pixmap.ColorCount);
end;

{ FCN_FillRect }

procedure FCN_FillRect.SimpleFunction;
var
  Pixmap: TASPixmap;
  Left, Top, Width, Height: Integer;
  Color: TRGB;
begin

  Args
    .Extract(Pixmap)
    .ExtractNonNeg(Left)
    .ExtractNonNeg(Top)
    .ExtractNonNeg(Width)
    .ExtractNonNeg(Height)
    .Extract(Color, clBlack);

  Pixmap.FillRect(Rect(Left, Top, Left + Width, Top + Height), Color);
  Result := ASO(Pixmap);

end;

{ FCN_DrawRect }

procedure FCN_DrawRect.SimpleFunction;
var
  BgPixmap, FgPixmap: TASPixmap;
  Left, Top: Integer;
  Opacity: TASR;
  BlendMode: string;
begin

  Args
    .Extract(BgPixmap)
    .Extract(FgPixmap)
    .ExtractNonNeg(Left, 0)
    .ExtractNonNeg(Top, 0)
    .Extract(Opacity, 1)
    .Extract(BlendMode, 'normal')
    .Close;

  BgPixmap.Draw(FgPixmap, Left, Top, Opacity, TBlendMode.FromString(BlendMode));
  Result := ASO(BgPixmap);

end;

{ FCN_AlphaDrawRect }

procedure FCN_AlphaDrawRect.SimpleFunction;
var
  BgPixmap, FgPixmap: TASPixmap;
  Left, Top: Integer;
  Opacity: TASR;
  BlendMode: string;
begin

  Args
    .Extract(BgPixmap)
    .Extract(FgPixmap)
    .ExtractNonNeg(Left, 0)
    .ExtractNonNeg(Top, 0)
    .Extract(Opacity, 1)
    .Extract(BlendMode, 'normal')
    .Close;

  BgPixmap.AlphaDraw(FgPixmap, Left, Top, Opacity, TBlendMode.FromString(BlendMode));
  Result := ASO(BgPixmap);

end;

{ FCN_FixHue }

procedure FCN_FixHue.SimpleFunction;
var
  Color: TRGB;
  Pixmap: TASPixmap;
  LHue: TASR;
begin

  if Args.PeekAt(0) is TAlgosimPixmap then
  begin
    Args.Extract(Pixmap).Extract(LHue).Close;
    Pixmap.FixHue(LHue);
    Result := ASO(Pixmap);
    Exit;
  end;

  Args.Extract(Color).Extract(LHue).Close;
  with THSV(Color) do
    Result := ASO(THSV.Create(LHue, Saturation, Value));

end;

{ FCN_ToMonochromatic }

procedure FCN_ToMonochromatic.SimpleFunction;
var
  Color: TRGB;
  Pixmap: TASPixmap;
  LHue: TASR;
begin

  if Args.PeekAt(0) is TAlgosimPixmap then
  begin
    Args.Extract(Pixmap).Extract(LHue).Close;
    Pixmap.ToMonochromatic(LHue);
    Result := ASO(Pixmap);
    Exit;
  end;

  Args.Extract(Color).Extract(LHue).Close;
  with THSV(Color) do
    Result := ASO(THSV.Create(LHue, 1, Value));

end;

{ FCN_ShiftHue }

procedure FCN_ShiftHue.SimpleFunction;
var
  Color: TRGB;
  Pixmap: TASPixmap;
  Amount: TASR;
begin

  if Args.PeekAt(0) is TAlgosimPixmap then
  begin
    Args.Extract(Pixmap).Extract(Amount).Close;
    Pixmap.ShiftHue(Amount);
    Result := ASO(Pixmap);
    Exit;
  end;

  Args.Extract(Color).Extract(Amount).Close;
  with THSV(Color) do
    Result := ASO(THSV.Create(Hue + Amount, Saturation, Value));

end;

{ FCN_ToGreyscale }

procedure FCN_ToGreyscale.SimpleFunction;
var
  Color: TRGB;
  Pixmap: TASPixmap;
begin

  if Args.PeekAt(0) is TAlgosimPixmap then
  begin
    Args.Extract(Pixmap).Close;
    Pixmap.ToGreyscale;
    Result := ASO(Pixmap);
    Exit;
  end;

  Args.Extract(Color).Close;
  with THSV(Color) do
    Result := ASO(THSV.Create(Hue, 0, Value));

end;

{ FCN_InvertColor }

procedure FCN_InvertColor.SimpleFunction;
var
  Color: TRGB;
  Pixmap: TASPixmap;
begin

  if Args.PeekAt(0) is TAlgosimPixmap then
  begin
    Args.Extract(Pixmap).Close;
    Pixmap.Invert;
    Result := ASO(Pixmap);
    Exit;
  end;

  Args.Extract(Color).Close;
  Result := ASO(InvertColor(Color));

end;

{ FCN_InvertValue }

procedure FCN_InvertValue.SimpleFunction;
var
  Color: TRGB;
  Pixmap: TASPixmap;
begin

  if Args.PeekAt(0) is TAlgosimPixmap then
  begin
    Args.Extract(Pixmap).Close;
    Pixmap.InvertValue;
    Result := ASO(Pixmap);
    Exit;
  end;

  Args.Extract(Color).Close;
  Result := ASO(InvertValue(Color));

end;

{ FCN_InvertLightness }

procedure FCN_InvertLightness.SimpleFunction;
var
  Color: TRGB;
  Pixmap: TASPixmap;
begin

  if Args.PeekAt(0) is TAlgosimPixmap then
  begin
    Args.Extract(Pixmap).Close;
    Pixmap.InvertLightness;
    Result := ASO(Pixmap);
    Exit;
  end;

  Args.Extract(Color).Close;
  Result := ASO(InvertLightness(Color));

end;

{ FCN_RGBAdjustment }

procedure FCN_RGBAdjustment.SimpleFunction;
resourcestring
  SInvRGBAdjMat = 'The RGB adjustment matrix must be a real 3×5 matrix.';
var
  Pixmap: TASPixmap;
  Mat: TRealMatrix;
  Params: TRGBAdjustmentParameters;
  i: Integer;
begin

  Args.Extract(Pixmap).Extract(Mat).Close;

  if Mat.Size <> TMatrixSize.Create(3, 5) then
    raise EInvArgs.Create(SInvRGBAdjMat);

  Params.Init;
  for i := 0 to 2 do
    with Params.ComponentParts[i] do
    begin
      Constant := Mat[i, 0];
      RedFactor := Mat[i, 1];
      GreenFactor := Mat[i, 2];
      BlueFactor := Mat[i, 3];
      Overflow := not IsZero(Mat[i, 4]);
    end;

  Pixmap.RGBAdjustments(Params);
  Result := ASO(Pixmap);

end;

{ FCN_HSVAdjustment }

procedure FCN_HSVAdjustment.SimpleFunction;
resourcestring
  SInvHSVAdjMat = 'The HSV adjustment matrix must be a real 3×5 matrix.';
var
  Pixmap: TASPixmap;
  Mat: TRealMatrix;
  Params: THSVAdjustmentParameters;
  i: Integer;
begin

  Args.Extract(Pixmap).Extract(Mat).Close;

  if Mat.Size <> TMatrixSize.Create(3, 5) then
    raise EInvArgs.Create(SInvHSVAdjMat);

  Params.Init;
  for i := 0 to 2 do
    with Params.ComponentParts[i] do
    begin
      Constant := Mat[i, 0];
      HueFactor := Mat[i, 1];
      SaturationFactor := Mat[i, 2];
      ValueFactor := Mat[i, 3];
      Overflow := not IsZero(Mat[i, 4]);
    end;

  Pixmap.HSVAdjustments(Params);
  Result := ASO(Pixmap);

end;

{ FCN_Binarize }

procedure FCN_Binarize.SimpleFunction;
var
  Pixmap: TASPixmap;
  Threshold: TASR;
begin
  Args.Extract(Pixmap).Extract(Threshold, 0.5).Close;
  Pixmap.Binarize(Threshold);
  Result := ASO(Pixmap);
end;

{ FCN_Flip }

procedure FCN_Flip.SimpleFunction;
var
  Pixmap: TASPixmap;
  Direction: Char;
begin
  Args.Extract(Pixmap).Extract(Direction, ['h', 'v'], 'h').Close;
  case Direction of
    'h':
      Pixmap.FlipHorizontally;
    'v':
      Pixmap.FlipVertically;
  end;
  Result := ASO(Pixmap);
end;

{ FCN_Rot90P }

procedure FCN_Rot90P.SimpleFunction;
var
  Pixmap: TASPixmap;
begin
  Args.Extract(Pixmap).Close;
  Pixmap.Rot90P;
  Result := ASO(Pixmap);
end;

{ FCN_Rot90N }

procedure FCN_Rot90N.SimpleFunction;
var
  Pixmap: TASPixmap;
begin
  Args.Extract(Pixmap).Close;
  Pixmap.Rot90N;
  Result := ASO(Pixmap);
end;

{ FCN_Rot180 }

procedure FCN_Rot180.SimpleFunction;
var
  Pixmap: TASPixmap;
begin
  Args.Extract(Pixmap).Close;
  Pixmap.Rot180;
  Result := ASO(Pixmap);
end;

{ FCN_ScanlineRotation }

procedure FCN_ScanlineRotation.SimpleFunction;
var
  Pixmap: TASPixmap;
  Amount: Integer;
  Direction: Char;
begin

  Args
    .Extract(Pixmap)
    .Extract(Amount)
    .Extract(Direction, ['h', 'v'], 'h')
    .Close;

  case Direction of
    'h':
      Pixmap.HorizontalRotation(Amount);
    'v':
      Pixmap.VerticalRotation(Amount);
  end;

  Result := ASO(Pixmap);

end;

{ FCN_CustomScanlineRotation }

procedure FCN_CustomScanlineRotation.DoExecute;
const
  ARG_INDEX_OBJECT = 0;
  ARG_INDEX_SYMBOL = 1;
  ARG_INDEX_EXPRESSION = 2;
  ARG_INDEX_DIRECTION = 3;
var
  symbol: string;
  symbols: TList<TASExprNode>;
  ResPm: TASPixmap;
  Direction: Char;
  f: TFunc<Integer, Integer>;
begin

  CheckNumArgs([3, 4]);
  CheckSymbol(ARG_INDEX_SYMBOL);
  symbol := TASSymbolExprNode(Children[ARG_INDEX_SYMBOL]).Symbol;

  if not EvalChild(ARG_INDEX_OBJECT) then Exit;
  if not EvalChildren(3) then Exit;
  Args.Extract(ResPm).Skip.Skip.Extract(Direction, ['h', 'v'], 'h').Close;

  f := function(X: Integer): Integer
    var
      res: TAlgosimObject;
    begin
      PopulateSymbols(symbols, ASOInt(X));
      Children[ARG_INDEX_EXPRESSION].Evaluate;
      res := Children[ARG_INDEX_EXPRESSION].Value;
      CheckFailure(res);
      if not res.TryToInt32(Result) then
        raise EInvArgs.Create('Expression must evaluate to an integer.');
    end;

  symbols := TList<TASExprNode>.Create;
  try

    FindSymbols(Children[ARG_INDEX_EXPRESSION], symbol, symbols);

    case Direction of
      'h':
        ResPm.CustomHorizontalRotation(f);
      'v':
        ResPm.CustomVerticalRotation(f);
    end;

  finally
    symbols.Free;
  end;

  Result := ASO(ResPm);

end;

{ FCN_SkewRotation }

procedure FCN_SkewRotation.SimpleFunction;
var
  Pixmap: TASPixmap;
  Delta, Denom: Integer;
  Direction: Char;
begin

  Args
    .Extract(Pixmap)
    .Extract(Delta)
    .Extract(Denom, 100)
    .Extract(Direction, ['h', 'v'], 'h')
    .Close;

  case Direction of
    'h':
      Pixmap.HorizontalSkewRotation(Delta, Denom);
    'v':
      Pixmap.VerticalSkewRotation(Delta, Denom);
  end;

  Result := ASO(Pixmap);

end;

{ FCN_Scale }

procedure FCN_Scale.SimpleFunction;
var
  Pixmap: TASPixmap;
  Factor: TASR;
begin
  Args.Extract(Pixmap).Extract(Factor).Close;
  Pixmap.Scale(Factor);
  Result := ASO(Pixmap);
end;

{ FCN_Stretch }

procedure FCN_Stretch.SimpleFunction;
var
  Pixmap: TASPixmap;
  FactorX, FactorY: TASR;
begin
  Args.Extract(Pixmap).Extract(FactorX).Extract(FactorY, FactorX).Close;
  Pixmap.Stretch(FactorX, FactorY);
  Result := ASO(Pixmap);
end;

{ FCN_Rotate }

procedure FCN_Rotate.SimpleFunction;
var
  Pixmap: TASPixmap;
  Angle: TASR;
begin
  Args.Extract(Pixmap).Extract(Angle).Close;
  Pixmap.Rotate(Angle);
  Result := ASO(Pixmap);
end;

{ FCN_Shear }

procedure FCN_Shear.SimpleFunction;
var
  Pixmap: TASPixmap;
  Angle: TASR;
begin
  Args.Extract(Pixmap).Extract(Angle).Close;
  Pixmap.Shear(Angle);
  Result := ASO(Pixmap);
end;

{ FCN_ApplyLinearTransformation }

procedure FCN_ApplyLinearTransformation.SimpleFunction;
var
  Pixmap: TASPixmap;
  Mat: TRealMatrix;
begin
  Args.Extract(Pixmap).Extract(Mat).Close;
  Pixmap.LinearTransform(Mat);
  Result := ASO(Pixmap);
end;

{ FCN_ApplyTransformation }

procedure FCN_ApplyTransformation.DoExecute;
const
  ARG_INDEX_OBJECT = 0;
  ARG_INDEX_SYMBOL = 1;
  ARG_INDEX_EXPRESSION = 2;
var
  symbol: string;
  symbols: TList<TASExprNode>;
  ResPm: TASPixmap;
begin

  CheckNumArgs(3);
  CheckSymbol(ARG_INDEX_SYMBOL);
  symbol := TASSymbolExprNode(Children[ARG_INDEX_SYMBOL]).Symbol;

  if not EvalChild(ARG_INDEX_OBJECT) then Exit;
  Args.Extract(ResPm);

  symbols := TList<TASExprNode>.Create;
  try
    FindSymbols(Children[ARG_INDEX_EXPRESSION], symbol, symbols);

    ResPm.CustomTransform(
      function(const X: TRealVector): TRealVector
      var
        res: TAlgosimObject;
      begin
        PopulateSymbols(symbols, ASO(X));
        Children[ARG_INDEX_EXPRESSION].Evaluate;
        res := Children[ARG_INDEX_EXPRESSION].Value;
        CheckFailure(Children[ARG_INDEX_EXPRESSION].Value);
        if res is TAlgosimVector then
          Result := res.AsRealVector
        else
          raise EInvArgs.Create('Pixmap transformation function must return a two-dimensional real vector.');
      end
    );

  finally
    symbols.Free;
  end;

  Result := ASO(ResPm);

end;

{ FCN_GetRect }

procedure FCN_GetRect.SimpleFunction;
var
  Left, Top, Width, Height: Integer;
  Pixmap: TASPixmap;
begin

  Args
    .Extract(Pixmap)
    .ExtractNonNeg(Left)
    .ExtractNonNeg(Top)
    .ExtractNonNeg(Width)
    .ExtractNonNeg(Height)
    .Close;

  Result := ASO(Pixmap.GetRect(
    Rect(
      Left,
      Top,
      Left + Width,
      Top + Height
    )
  ));

end;

{ FCN_AverageColor }

procedure FCN_AverageColor.SimpleFunction;
var
  Pixmap: TASPixmap;
  Left, Top, Width, Height: Integer;
  R: TRect;
const
  MaxPixelCount = UInt64.MaxValue div 255;
begin

  CheckNumArgs([1, 5]);

  Args
    .Extract(Pixmap)
    .ExtractNonNeg(Left, 0)
    .ExtractNonNeg(Top, 0)
    .ExtractNonNeg(Width, Pixmap.Width)
    .ExtractNonNeg(Height, Pixmap.Height)
    .Close;

  R := Rect(Left, Top, Left + Width, Top + Height);

  if Width * Height <= MaxPixelCount then
    Result := ASO(Pixmap.AverageColor(R))
  else
    Result := ASO(Pixmap.AverageColorF(R));

end;

{ FCN_GetAutoCropRect }

procedure FCN_GetAutoCropRect.SimpleFunction;
var
  Pixmap: TASPixmap;
begin
  Args.Extract(Pixmap).Close;
  Result := ASOIntRect(Pixmap.GetAutoCropRect);
end;

{ FCN_AutoCrop }

procedure FCN_AutoCrop.SimpleFunction;
var
  Pixmap: TASPixmap;
begin
  Args.Extract(Pixmap).Close;
  Pixmap.AutoCrop;
  Result := ASO(Pixmap);
end;

{ FCN_ExpandCanvas }

procedure FCN_ExpandCanvas.SimpleFunction;
var
  Pixmap: TASPixmap;
  Width, Height: Integer;
begin
  Args.Extract(Pixmap).ExtractNonNeg(Width).ExtractNonNeg(Height, Width).Close;
  Result := ASO(Pixmap.CloneWithBorder(Width, Height, Pixmap.BackgroundColor));
end;

{ FCN_OnlyBackground }

procedure FCN_OnlyBackground.SimpleFunction;
var
  Pixmap: TASPixmap;
begin
  Args.Extract(Pixmap).Close;
  Result := ASO(Pixmap.OnlyBackground);
end;

{ FCN_DetectEdges }

procedure FCN_DetectEdges.SimpleFunction;
var
  Pixmap: TASPixmap;
  DirectionFlags: TSysCharSet;
  Directions: TEdgeDetectionDirections;
begin

  Args
    .Extract(Pixmap)
    .Extract(DirectionFlags, restr, ['v', 'h'], defval, ['v', 'h'])
    .Close;

  Directions := [];
  if AnsiChar('h') in DirectionFlags then
    Include(Directions, eddHorizontal);
  if AnsiChar('v') in DirectionFlags then
    Include(Directions, eddVertical);

  Pixmap.EdgeDetect(Directions);
  Result := ASO(Pixmap);

end;

{ FCN_Emboss }

procedure FCN_Emboss.SimpleFunction;
var
  Pixmap: TASPixmap;
  DirectionFlags: TSysCharSet;
  Directions: TEdgeDetectionDirections;
begin

  Args
    .Extract(Pixmap)
    .Extract(DirectionFlags, restr, ['v', 'h'], defval, ['v', 'h'])
    .Close;

  Directions := [];
  if AnsiChar('h') in DirectionFlags then
    Include(Directions, eddHorizontal);
  if AnsiChar('v') in DirectionFlags then
    Include(Directions, eddVertical);

  Pixmap.Emboss(Directions);
  Result := ASO(Pixmap);

end;

{ FCN_Pixellate }

procedure FCN_Pixellate.SimpleFunction;
var
  Pixmap: TASPixmap;
  XSize, YSize: Integer;
begin
  Args.Extract(Pixmap).ExtractPos(XSize).ExtractPos(YSize, XSize).Close;
  Pixmap.Pixelate(XSize, YSize);
  Result := ASO(Pixmap);
end;

{ FCN_Noise }

procedure FCN_Noise.SimpleFunction;
var
  Pixmap: TASPixmap;
  Probability: TASR;
  Color: TRGB;
begin
  Args.Extract(Pixmap).Extract(Probability, 0.5).Extract(Color, clWhite).Close;
  Pixmap.Noise(Probability, Color);
  Result := ASO(Pixmap);
end;

{ FCN_DistortMetric }

procedure FCN_DistortMetric.SimpleFunction;
var
  Pixmap: TASPixmap;
  RadiusX, RadiusY: Integer;
begin
  Args.Extract(Pixmap).ExtractNonNeg(RadiusX).ExtractNonNeg(RadiusY, RadiusX).Close;
  Pixmap.DistortMetric(RadiusX, RadiusY);
  Result := ASO(Pixmap);
end;

{ FCN_DistortColor }

procedure FCN_DistortColor.SimpleFunction;
var
  Pixmap: TASPixmap;
  Red, Green, Blue: Integer;
begin
  Args
    .Extract(Pixmap)
    .ExtractNonNeg(Red)
    .ExtractNonNeg(Green, Red)
    .ExtractNonNeg(Blue, Green)
    .Close;
  Pixmap.DistortColor(Red, Green, Blue);
  Result := ASO(Pixmap);
end;

{ FCN_Tiles }

procedure FCN_Tiles.SimpleFunction;
var
  Pixmap: TASPixmap;
  NumRows, NumCols: Integer;
  Padding: Integer;
  Shuffle: Boolean;
begin
  Args
    .Extract(Pixmap)
    .Extract(NumRows)
    .Extract(NumCols)
    .ExtractNonNeg(Padding, 1)
    .Extract(Shuffle, True)
    .Close;
  Pixmap.Tiles(NumRows, NumCols, Padding, Shuffle);
  Result := ASO(Pixmap);
end;

{ FCN_ComponentHighlight }

procedure FCN_ComponentHighlight.SimpleFunction;
var
  Pixmap: TASPixmap;
  Fcn: TAlgosimFunctionObject;
begin
  Args.Extract(Pixmap).Extract(Fcn, nil).Close;
  if Fcn = nil then
    Pixmap.ComponentHighlight
  else
    Pixmap.ComponentHighlight(
      function(Idx: Integer): TColor
      var
        res: TAlgosimObject;
      begin
        res := Fcn.Execute(Context, [ASOInt(Idx + 1)], True);
        try
          Result := res.ToColor;
        finally
          res.Free;
        end;
      end);
  Result := ASO(Pixmap);
end;

{ FCN_FloodFill }

procedure FCN_FloodFill.SimpleFunction;
var
  Pixmap: TASPixmap;
  X, Y: Integer;
  Color: TRGB;
begin
  Args.Extract(Pixmap).ExtractNonNeg(X).ExtractNonNeg(Y).Extract(Color).Close;
  Pixmap.FloodFill(Point(X, Y), Color);
  Result := ASO(Pixmap);
end;

{ FCN_DrawLine }

procedure FCN_DrawLine.SimpleFunction;
var
  Pixmap: TASPixmap;
  X0, Y0, X1, Y1: Integer;
  Color: TRGB;
begin
  Args
    .Extract(Pixmap)
    .Extract(X0)
    .Extract(Y0)
    .Extract(X1)
    .Extract(Y1)
    .Extract(Color)
    .Close;
  Pixmap.DrawLine(Point(X0, Y0), Point(X1, Y1), Color);
  Result := ASO(Pixmap);
end;

{ FCN_DrawLines }

procedure FCN_DrawLines.SimpleFunction;
var
  Pixmap: TASPixmap;
  Points: TArray<TPoint>;
  Color: TRGB;
  P: TPoint;
  i: Integer;
begin
  Args
    .Extract(Pixmap)
    .Extract(Points)
    .Extract(Color)
    .Close;
  if Length(Points) > 0 then
  begin
    P := Points[0];
    for i := 1 to High(Points) do
    begin
      Pixmap.DrawLine(P, Points[i], Color);
      P := Points[i];
    end;
  end;
  Result := ASO(Pixmap);
end;

{ FCN_DrawPolygon }

procedure FCN_DrawPolygon.SimpleFunction;
var
  Pixmap: TASPixmap;
  Points: TArray<TPoint>;
  Color: TRGB;
  P: TPoint;
  i: Integer;
begin
  Args
    .Extract(Pixmap)
    .Extract(Points)
    .Extract(Color)
    .Close;
  if Length(Points) > 0 then
  begin
    P := Points[0];
    for i := 1 to High(Points) do
    begin
      Pixmap.DrawLine(P, Points[i], Color);
      P := Points[i];
    end;
    Pixmap.DrawLine(P, Points[0], Color);
  end;
  Result := ASO(Pixmap);
end;

{ FCN_Convolve }

procedure FCN_Convolve.SimpleFunction;
resourcestring
  SKernelMustBeOddSquare = 'Convolution kernel must be square with an odd number of rows.';
var
  Pixmap: TASPixmap;
  Kernel: TRealMatrix;
begin
  Args.Extract(Pixmap).Extract(Kernel).Close;
  if not (Kernel.Size.IsSquare and Odd(Kernel.Size.Rows)) then
    raise EInvArgs.Create(SKernelMustBeOddSquare);
  Pixmap.Convolve(Kernel);
  Result := ASO(Pixmap);
end;

{ FCN_ConvolutionKernel }

procedure FCN_ConvolutionKernel.SimpleFunction;
resourcestring
  SUnknownConvolutionKernel = 'Unknown convolution kernel "%s".';
var
  KernelName: string;
  k: TPredefinedKernel;
begin
  Args.Extract(KernelName).Close;
  for k := Low(TPredefinedKernel) to High(TPredefinedKernel) do
    if SameText(PredefinedKernelNames[k], KernelName) then
    begin
      Result := ASO(TASPixmap.GetPredefinedKernel(k));
      Exit;
    end;
  raise EInvArgs.CreateFmt(SUnknownConvolutionKernel, [KernelName]);
end;

{ FCN_MotionBlur }

procedure FCN_MotionBlur.SimpleFunction;
var
  Pixmap: TASPixmap;
  Amount: Integer;
  Direction: Char;
begin

  Args
    .Extract(Pixmap)
    .ExtractNonNeg(Amount, 32)
    .Extract(Direction, ['h', 'v'], 'h')
    .Close;

  case Direction of
    'h':
      Pixmap.MotionBlurH(Amount);
    'v':
      Pixmap.MotionBlurV(Amount);
  end;

  Result := ASO(Pixmap);

end;

{ FCN_BoxBlur }

procedure FCN_BoxBlur.SimpleFunction;
var
  Pixmap: TASPixmap;
  Amount: Integer;
begin
  Args.Extract(Pixmap).ExtractNonNeg(Amount, 2).Close;
  Pixmap.BoxBlur(Amount);
  Result := ASO(Pixmap);
end;

{ FCN_GaussianBlur }

procedure FCN_GaussianBlur.SimpleFunction;
var
  Pixmap: TASPixmap;
  Amount, Iterations: Integer;
begin
  Args.Extract(Pixmap).ExtractNonNeg(Amount, 2).ExtractNonNeg(Iterations, 6).Close;
  Pixmap.GaussianBlur(Amount, Iterations);
  Result := ASO(Pixmap);
end;

{ FCN_Darken }

procedure FCN_Darken.SimpleFunction;
var
  Color: TRGB;
  Pixmap: TASPixmap;
begin

  if Args.PeekAt(0) is TAlgosimPixmap then
  begin
    Args.Extract(Pixmap).Close;
    Pixmap.QuickFadeToBlack;
    Result := ASO(Pixmap);
    Exit;
  end;

  Args.Extract(Color).Close;
  Result := ASO(Darken(Color));

end;

{ FCN_Whiten }

procedure FCN_Whiten.SimpleFunction;
var
  Color: TRGB;
  Pixmap: TASPixmap;
begin

  if Args.PeekAt(0) is TAlgosimPixmap then
  begin
    Args.Extract(Pixmap).Close;
    Pixmap.QuickFadeToWhite;
    Result := ASO(Pixmap);
    Exit;
  end;

  Args.Extract(Color).Close;
  Result := ASO(Whiten(Color));

end;

{ FCN_FadeToColor }

procedure FCN_FadeToColor.SimpleFunction;
var
  Color: TRGB;
  Pixmap: TASPixmap;
  TargetColor: TRGB;
  Fraction: TASR;
begin

  if Args.PeekAt(0) is TAlgosimPixmap then
  begin
    Args.Extract(Pixmap).Extract(TargetColor).Extract(Fraction, 0.5).Close;
    Pixmap.FadeToColor(TargetColor, Fraction);
    Result := ASO(Pixmap);
    Exit;
  end;

  Args.Extract(Color).Extract(TargetColor).Extract(Fraction, 0.5).Close;
  Result := ASO(FadeToColor(Color, TargetColor, Fraction));

end;

{ FCN_EveryOtherToColor }

procedure FCN_EveryOtherToColor.SimpleFunction;
var
  Pixmap: TASPixmap;
  Fcn: TAlgosimFunctionObject;
  Color: TRGB;
  N: Integer;
begin

  if Args.PeekAt(1) is TAlgosimFunctionObject then
  begin
    Args.Extract(Pixmap).Extract(Fcn).Extract(N, 2).Close;
    Pixmap.EveryOtherToColor(
      function(X, Y: Integer): TColor // could be optimized
      var
        res: TAlgosimObject;
      begin
        res := Fcn.Execute(Context, [ASOInt(X), ASOInt(Y)], True);
        try
          Result := res.ToColor;
        finally
          res.Free;
        end;
      end, N);
  end
  else
  begin
    Args.Extract(Pixmap).Extract(Color).Extract(N, 2).Close;
    Pixmap.EveryOtherToColor(Color, N);
  end;

  Result := ASO(Pixmap);

end;

{ FCN_RandomToColor }

procedure FCN_RandomToColor.SimpleFunction;
var
  Pixmap: TASPixmap;
  Fcn: TAlgosimFunctionObject;
  Color: TRGB;
  prob: TASR;
begin

  if Args.PeekAt(1) is TAlgosimFunctionObject then
  begin
    Args.Extract(Pixmap).Extract(Fcn).Extract(prob, 0.5).Close;
    Pixmap.RandomToColor(
      function(X, Y: Integer): TColor // could be optimized
      var
        res: TAlgosimObject;
      begin
        res := Fcn.Execute(Context, [ASOInt(X), ASOInt(Y)], True);
        try
          Result := res.ToColor;
        finally
          res.Free;
        end;
      end, prob);
  end
  else
  begin
    Args.Extract(Pixmap).Extract(Color).ExtractNonNeg(prob, 0.5).Close;
    Pixmap.RandomToColor(Color, prob);
  end;

  Result := ASO(Pixmap);

end;

{ FCN_Wind }

procedure FCN_Wind.SimpleFunction;
var
  Pixmap: TASPixmap;
  Probability: TASR;
  Distance: Integer;
  Fading: TASR;
begin
  Args
    .Extract(Pixmap)
    .Extract(Probability)
    .Extract(Distance)
    .Extract(Fading)
    .Close;
  Pixmap.Wind(Probability, Distance, Fading);
  Result := ASO(Pixmap);
end;

{ FCN_RandomScanlineRotation }

procedure FCN_RandomScanlineRotation.SimpleFunction;
var
  Pixmap: TASPixmap;
  Amount: Integer;
  Direction: Char;
begin

  Args
    .Extract(Pixmap)
    .ExtractNonNeg(Amount, 12)
    .Extract(Direction, ['h', 'v'], 'h')
    .Close;

  case Direction of
    'h':
      Pixmap.RandomHorizontalRotation(Amount);
    'v':
      Pixmap.RandomVerticalRotation(Amount);
  end;

  Result := ASO(Pixmap);

end;

{ FCN_Ripple }

procedure FCN_Ripple.SimpleFunction;
var
  Pixmap: TASPixmap;
  Amplitude, Wavelength: Integer;
  Direction: char;
begin

  Args
    .Extract(Pixmap)
    .Extract(Amplitude)
    .Extract(Wavelength)
    .Extract(Direction, ['h', 'v'], 'h')
    .Close;

  case Direction of
    'h':
      Pixmap.RippleH(Amplitude, Wavelength);
    'v':
      Pixmap.RippleV(Amplitude, Wavelength);
  end;

  Result := ASO(Pixmap);

end;

{ FCN_ExtractChannel }

procedure FCN_ExtractChannel.SimpleFunction;
var
  Pixmap: TASPixmap;
  Family: string;
  Channel: char;
  Snd: TASSound;
  Idx: Integer;
begin

  if Args.PeekAt(0) is TAlgosimPixmap then
  begin

    Args
      .Extract(Pixmap)
      .Extract(Family, ['rgb', 'hsv', 'hsl'])
      .Extract(Channel, Family.ToCharArray)
      .Close;

    if SameText(Family, 'rgb') then
      case Channel.ToLower of
        'r':
          Result := ASO(Pixmap.ExtractRGBChannel(rgbRed));
        'g':
          Result := ASO(Pixmap.ExtractRGBChannel(rgbGreen));
        'b':
          Result := ASO(Pixmap.ExtractRGBChannel(rgbBlue));
      end
    else if SameText(Family, 'hsv') then
      case Channel.ToLower of
        'h':
          Result := ASO(Pixmap.ExtractHSVChannel(hsvHue));
        's':
          Result := ASO(Pixmap.ExtractHSVChannel(hsvSaturation));
        'v':
          Result := ASO(Pixmap.ExtractHSVChannel(hsvValue));
      end
    else if SameText(Family, 'hsl') then
      case Channel.ToLower of
        'h':
          Result := ASO(Pixmap.ExtractHSLChannel(hslHue));
        's':
          Result := ASO(Pixmap.ExtractHSLChannel(hslSaturation));
        'l':
          Result := ASO(Pixmap.ExtractHSLChannel(hslLightness));
      end

  end

  else if Args.PeekAt(0) is TAlgosimSound then
  begin

    Args.Extract(Snd).ExtractNonNeg(Idx).Close;
    Result := ASO(Snd.ExtractChannel(Idx));

  end

  else
    ErrInvalidArguments;

end;

{ FCN_CombineChannels }

procedure FCN_CombineChannels.SimpleFunction;
var
  Family: string;
  Ch1, Ch2, Ch3: TASPixmap;
begin

  Args
    .Extract(Family, ['rgb', 'hsv'])
    .Extract(Ch1)
    .Extract(Ch2)
    .Extract(Ch3)
    .Close;

  if SameText(Family, 'rgb') then
    Result := ASO(TASPixmap.RGBCombine(Ch1, Ch2, Ch3))
  else if SameText(Family, 'hsv') then
    Result := ASO(TASPixmap.HSVCombine(Ch1, Ch2, Ch3));

end;

{ FCN_IsGreyscale }

procedure FCN_IsGreyscale.SimpleFunction;
var
  Pixmap: TASPixmap;
begin
  Args.Extract(Pixmap).Close;
  Result := ASO(Pixmap.IsGreyscale);
end;

{ FCN_DrawDisk }

procedure FCN_DrawDisk.SimpleFunction;
var
  Pixmap: TASPixmap;
  X, Y: Integer;
  Radius: Integer;
  Color: TRGB;
begin

  Args
    .Extract(Pixmap)
    .Extract(X)
    .Extract(Y)
    .Extract(Color, clBlack)
    .Extract(Radius, 4)
    .Close;

  Pixmap.DrawDisk(Point(X, Y), Color, Radius);
  Result := ASO(Pixmap);

end;

{ FCN_DrawDisks }

procedure FCN_DrawDisks.SimpleFunction;
var
  Pixmap: TASPixmap;
  Points: TArray<TPoint>;
  Radius: Integer;
  Color: TRGB;
begin

  Args
    .Extract(Pixmap)
    .Extract(Points)
    .Extract(Color, clBlack)
    .Extract(Radius, 4)
    .Close;

  Pixmap.DrawDisks(Points, Color, Radius);
  Result := ASO(Pixmap);

end;

{ FCN_DrawSquare }

procedure FCN_DrawSquare.SimpleFunction;
var
  Pixmap: TASPixmap;
  X, Y: Integer;
  SideLength: Integer;
  Color: TRGB;
begin

  Args
    .Extract(Pixmap)
    .Extract(X)
    .Extract(Y)
    .Extract(Color, clBlack)
    .Extract(SideLength, 4)
    .Close;

  Pixmap.DrawSquare(Point(X, Y), Color, SideLength);
  Result := ASO(Pixmap);

end;

{ FCN_DrawSquares }

procedure FCN_DrawSquares.SimpleFunction;
var
  Pixmap: TASPixmap;
  Points: TArray<TPoint>;
  SideLength: Integer;
  Color: TRGB;
begin

  Args
    .Extract(Pixmap)
    .Extract(Points)
    .Extract(Color, clBlack)
    .Extract(SideLength, 4)
    .Close;

  Pixmap.DrawSquares(Points, Color, SideLength);
  Result := ASO(Pixmap);

end;

{ FCN_CreateGradient }

procedure FCN_CreateGradient.SimpleFunction;
var
  W, H: Integer;
  From, &To: TRGB;
begin
  Args.ExtractPos(W).ExtractPos(H).Extract(From).Extract(&To).Close;
  Result := ASO(TASPixmap.CreateGradient(W, H, From, &To));
end;

{ FCN_Voronoi }

procedure FCN_Voronoi.SimpleFunction;
var
  W, H: Integer;
  Sites: TArray<TPoint>;
  Colors: TAlgosimArray;
  PixelArr: TArray<TASPixel>;
  i: Integer;
begin
  Args.ExtractPos(W).ExtractPos(H).Extract(Sites).Extract(Colors).Close;
  SetLength(PixelArr, Colors.ElementCount);
  for i := 0 to High(PixelArr) do
    PixelArr[i] := Colors.Elements[i + 1].ToColor;
  Result := ASO(TASPixmap.Voronoi(W, H, Sites, PixelArr));
end;

{ FCN_SuperposeSounds }

procedure FCN_SuperposeSounds.SimpleFunction;
var
  Snd1, Snd2: TASSound;
  StartPos: TASR;
  Coeff1, Coeff2: TASR;
begin
  Args
    .Extract(Snd1)
    .Extract(Snd2)
    .Extract(StartPos, 0)
    .Extract(Coeff1, 0.5)
    .Extract(Coeff2, 0.5)
    .Close;
  Result := ASO(Snd1.Superpose(Snd2, StartPos, Coeff1, Coeff2));
end;

{ FCN_AppendSound }

procedure FCN_AppendSound.SimpleFunction;
var
  Snd1, Snd2: TASSound;
begin
  Args.Extract(Snd1).Extract(Snd2).Close;
  Snd1.Append(Snd2);
  Result := ASO(Snd1);
end;

{ FCN_EchoSound }

procedure FCN_EchoSound.SimpleFunction;
var
  Snd: TASSound;
  Delay, Intensity: TASR;
begin
  Args.Extract(Snd).Extract(Delay, 0.4).Extract(Intensity, 0.4).Close;
  Result := ASO(Snd.Echo(Delay, Intensity));
end;

{ FCN_SoundScaleAmplitude }

procedure FCN_SoundScaleAmplitude.SimpleFunction;
var
  Snd: TASSound;
  Factor: TASR;
begin
  Args.Extract(Snd).Extract(Factor).Close;
  Result := ASO(Snd.ScaleAmplitude(Factor));
end;

{ FCN_SoundConvertTo }

procedure FCN_SoundConvertTo.SimpleFunction;
var
  Snd: TASSound;
  BitsPerSample: Integer;
begin
  Args.Extract(Snd).ExtractPos(BitsPerSample).Close;
  Result := ASO(Snd.ConvertTo(BitsPerSample));
end;

{ FCN_SineTone }

procedure FCN_SineTone.SimpleFunction;
var
  Freq, Amplitude, Duration: TASR;
  BitsPerSample, SampleFreq: Integer;
begin
  Args
    .ExtractPos(Freq, 400)
    .ExtractPos(Amplitude, 0.5)
    .ExtractPos(Duration, 2)
    .ExtractPos(BitsPerSample, 32)
    .ExtractPos(SampleFreq, HIGH_QUALITY_SAMPLE_RATE)
    .Close;
  Result := ASO(SineTone(Freq, Amplitude, Duration, BitsPerSample, SampleFreq));
end;

{ FCN_WhiteNoise }

procedure FCN_WhiteNoise.SimpleFunction;
var
  Amplitude, Duration: TASR;
  SampleFreq: Integer;
begin
  Args
    .ExtractPos(Amplitude, 0.5)
    .ExtractPos(Duration, 2)
    .ExtractPos(SampleFreq, HIGH_QUALITY_SAMPLE_RATE)
    .Close;
  Result := ASO(WhiteNoise(Amplitude, Duration, SampleFreq));
end;

{ FCN_MultichannelSound }

procedure FCN_MultichannelSound.SimpleFunction;
var
  Snd1, Snd2: TASSound;
  mask: Integer;
  Sounds: TArray<TASSound>;
begin

  if Args.PeekAt(0) is TAlgosimSound then
  begin
    Args.Extract(Snd1).Extract(Snd2).Close;
    Result := ASO(MultichannelSound([Snd1, Snd2], KSAUDIO_SPEAKER_STEREO));
  end
  else
  begin
    Args.Extract(Sounds).Extract(mask).Close;
    Result := ASO(MultichannelSound(Sounds, mask));
  end;

end;

{ FCN_FadeSounds }

procedure FCN_FadeSounds.SimpleFunction;
var
  Snd1, Snd2: TASSound;
  Duration: TASR;
begin
  Args
    .Extract(Snd1)
    .Extract(Snd2)
    .ExtractPos(Duration, 1)
    .Close;
  Result := ASO(FadeSound(Snd1, Snd2, Duration));
end;

{ FCN_ComputeSound }

procedure FCN_ComputeSound.DoExecute;
resourcestring
  SWaveDisplacementRealNumber = 'Wave displacement must be a real number.';
const
  ARG_INDEX_EXPRESSION = 0;
  ARG_INDEX_SYMBOL = 1;
  ARG_INDEX_BEGIN = 2;
  ARG_INDEX_END = 3;
  ARG_INDEX_AMPLITUDE = 4;
  ARG_INDEX_SAMPLE_FREQ = 5;
var
  Amplitude, &Begin, &End: TASR;
  symbol: string;
  symbols: TList<TASExprNode>;
  ResSnd: TASSound;
  SampleFreq: Integer;
begin

  CheckNumArgsAtLeast(2);
  CheckSymbol(ARG_INDEX_SYMBOL);
  symbol := TASSymbolExprNode(Children[ARG_INDEX_SYMBOL]).Symbol;

  if not EvalChildren(ARG_INDEX_BEGIN) then Exit;

  Args
    .Skip
    .Skip
    .Extract(&Begin)
    .Extract(&End)
    .ExtractNonNeg(Amplitude, 1)
    .ExtractPos(SampleFreq, HIGH_QUALITY_SAMPLE_RATE)
    .Close;

  symbols := TList<TASExprNode>.Create;
  try
    FindSymbols(Children[ARG_INDEX_EXPRESSION], symbol, symbols);

    ResSnd := GenerateSound(
      function(const t: Double): Double
      var
        res: TAlgosimObject;
        resval: TASR;
      begin
        PopulateSymbols(symbols, ASO(t));
        Children[ARG_INDEX_EXPRESSION].Evaluate;
        res := Children[ARG_INDEX_EXPRESSION].Value;
        CheckFailure(res);
        if (res is TAlgosimNumber) and res.TryToASR(resval) then
          Result := resval
        else
          raise EInvArgs.Create(SWaveDisplacementRealNumber);
      end,
      Amplitude,
      &Begin,
      &End,
      SampleFreq
    );

  finally
    symbols.Free;
  end;

  Result := ASO(ResSnd);

end;

{ FCN_SoundMetadata }

procedure FCN_SoundMetadata.DoExecute;
var
  Snd: TAlgosimSound;
begin
  CheckNumArgs(1);
  if not ExtractRef<TAlgosimSound>(0, Snd) then Exit;
  Result := ASO(
      [
        sm('duration', ASO(Snd.Value.Duration)),
        sm('SampleFreq', ASOInt(Snd.Value.SampleFrequency)),
        sm('SampleLen', ASOInt(Snd.Value.SampleLength)),
        sm('ByteLen', ASOInt(Snd.Value.DataLength)),
        sm('bitdepth', ASOInt(Snd.Value.BitsPerSample)),
        sm('channels', ASOInt(Snd.Value.ChannelCount)),
        sm('ChannelMask', ASOInt(Snd.Value.ChannelMask))
      ]
    );
end;

{ FCN_SoundMax }

procedure FCN_SoundMax.DoExecute;
var
  Snd: TAlgosimSound;
begin
  CheckNumArgs(1);
  if not ExtractRef<TAlgosimSound>(0, Snd) then Exit;
  Result := ASO(Snd.Value.MaxFraction);
end;

{ FCN_PlaySound }

procedure FCN_PlaySound.SimpleFunction;
var
  Snd: TASSound;
begin
  Args.Extract(Snd).Close;
  Result := TAlgosimSuccessIndication.CreateWithValue(
      Context.Perform(CLIENT_COMMAND_PLAYSOUND, NativeInt(@Snd))
    );
end;

{ FCN_StopSound }

procedure FCN_StopSound.SimpleFunction;
begin
  Args.Close;
  Result := TAlgosimSuccessIndication.CreateWithValue(
      Context.Perform(CLIENT_COMMAND_STOPSOUND)
    );
end;

{ FCN_SetInstrument }

function __InstrumentFromObj(Obj: TAlgosimObject): TMIDIInstrument;
resourcestring
  SUnknownInstrument = 'Unknown instrument "%s".';
var
  intval: Integer;
  strval: string;
begin
  if
    (Obj is TAlgosimNumber) and
    Obj.TryToInt32(intval) and
    InRange(intval, Ord(Low(TMIDIInstrument)), Ord(High(TMIDIInstrument)))
  then
    Result := TMIDIInstrument(intval)
  else if Obj is TAlgosimString then
  begin
    strval := Obj.ToString;
    intval := IndexText(strval, MIDI_INSTRUMENT_NAMES);
    if intval <> -1 then
      Result := TMIDIInstrument(intval)
    else
      raise EInvArgs.CreateFmt(SUnknownInstrument, [strval]);
  end
  else
    ErrInvalidArguments;
end;

function __PercussionKeyFromObj(Obj: TAlgosimObject): TMIDIPercussionKey;
resourcestring
  SUnknownPercussionInstrument = 'Unknown percussion instrument "%s".';
var
  intval: Integer;
  strval: string;
begin
  if
    (Obj is TAlgosimNumber) and
    Obj.TryToInt32(intval) and
    InRange(intval, Ord(Low(TMIDIPercussionKey)), Ord(High(TMIDIPercussionKey)))
  then
    Result := TMIDIPercussionKey(intval)
  else if Obj is TAlgosimString then
  begin
    strval := Obj.ToString;
    intval := Ord(Low(TMIDIPercussionKey)) + IndexText(strval, MIDI_PERCUSSION_INSTRUMENTS);
    if intval <> Pred(Ord(Low(TMIDIPercussionKey))) then
      Result := TMIDIPercussionKey(intval)
    else
      raise EInvArgs.CreateFmt(SUnknownPercussionInstrument, [strval]);
  end
  else
    ErrInvalidArguments;
end;

procedure FCN_SetInstrument.SimpleFunction;
var
  Obj: TAlgosimObject;
  Instrument: TMIDIInstrument;
begin

  Args.Extract(Obj).Close;
  Instrument := __InstrumentFromObj(Obj);

  Result := TAlgosimSuccessIndication.CreateWithValue(
      Context.Perform(CLIENT_COMMAND_MIDI_SETINSTRUMENT, Ord(Instrument))
    );

end;

{ FCN_GetInstrument }

procedure FCN_GetInstrument.SimpleFunction;
var
  Instrument: Integer;
begin
  Args.Close;
  Instrument := -1;
  if Context.Perform(CLIENT_COMMAND_MIDI_GETINSTRUMENT, NativeInt(@Instrument))
    and InRange(Instrument, Ord(Low(TMIDIInstrument)), Ord(High(TMIDIInstrument)))
  then
    Result := ASOInt(Instrument, fsMidiInstrument)
  else
    Result := ASO(failure);
end;

{ FCN_SetVolume }

procedure FCN_SetVolume.SimpleFunction;
var
  Vol: Integer;
begin
  Args.ExtractNonNeg(Vol).Close;
  if InRange(Vol, Word.MinValue, Word.MaxValue) then
    Result := TAlgosimSuccessIndication.CreateWithValue(
        Context.Perform(CLIENT_COMMAND_MIDI_SETVOLUME, Vol)
      )
  else
    ErrInvalidArguments;
end;

{ FCN_GetVolume }

procedure FCN_GetVolume.SimpleFunction;
var
  Vol: Integer;
begin
  Args.Close;
  Vol := -1;
  if Context.Perform(CLIENT_COMMAND_MIDI_GETVOLUME, NativeInt(@Vol))
    and InRange(Vol, Word.MinValue, Word.MaxValue)
  then
    Result := ASOInt(Vol)
  else
    Result := ASO(failure);
end;

{ FCN_NoteOn }

procedure FCN_NoteOn.SimpleFunction;
var
  Note, Vel: Integer;
begin
  Args.ExtractNonNeg(Note).ExtractNonNeg(Vel).Close;
  if InRange(Note, Low(TMIDIInt), High(TMIDIInt)) and
    InRange(Vel, Low(TMIDIInt), High(TMIDIInt))
  then
    Result := TAlgosimSuccessIndication.CreateWithValue(
        Context.Perform(CLIENT_COMMAND_MIDI_NOTEON, Note, Vel)
      )
  else
    ErrInvalidArguments;
end;

{ FCN_NoteOff }

procedure FCN_NoteOff.SimpleFunction;
var
  Note, Vel: Integer;
begin
  Args.ExtractNonNeg(Note).ExtractNonNeg(Vel).Close;
  if InRange(Note, Low(TMIDIInt), High(TMIDIInt)) and
    InRange(Vel, Low(TMIDIInt), High(TMIDIInt))
  then
    Result := TAlgosimSuccessIndication.CreateWithValue(
        Context.Perform(CLIENT_COMMAND_MIDI_NOTEOFF, Note, Vel)
      )
  else
    ErrInvalidArguments;
end;

{ FCN_PNoteOn }

procedure FCN_PNoteOn.SimpleFunction;
var
  Obj: TAlgosimObject;
  Instrument: TMIDIPercussionKey;
  Vel: Integer;
begin
  Args.Extract(Obj).ExtractNonNeg(Vel).Close;
  Instrument := __PercussionKeyFromObj(Obj);
  if InRange(Vel, Low(TMIDIInt), High(TMIDIInt)) then
    Result := TAlgosimSuccessIndication.CreateWithValue(
        Context.Perform(CLIENT_COMMAND_MIDI_PNOTEON, Ord(Instrument), Vel)
      )
  else
    ErrInvalidArguments;
end;

{ FCN_PNoteOff }

procedure FCN_PNoteOff.SimpleFunction;
var
  Obj: TAlgosimObject;
  Instrument: TMIDIPercussionKey;
  Vel: Integer;
begin
  Args.Extract(Obj).ExtractNonNeg(Vel).Close;
  Instrument := __PercussionKeyFromObj(Obj);
  if InRange(Vel, Low(TMIDIInt), High(TMIDIInt)) then
    Result := TAlgosimSuccessIndication.CreateWithValue(
        Context.Perform(CLIENT_COMMAND_MIDI_PNOTEOFF, Ord(Instrument), Vel)
      )
  else
    ErrInvalidArguments;
end;

{ FCN_NoteSilence }

procedure FCN_NoteSilence.SimpleFunction;
var
  Force: Boolean;
begin
  Args.Extract(Force, False).Close;
  if Force then
    Result := TAlgosimSuccessIndication.CreateWithValue(
        Context.Perform(CLIENT_COMMAND_MIDI_FORCEDSILENCE)
      )
  else
    Result := TAlgosimSuccessIndication.CreateWithValue(
        Context.Perform(CLIENT_COMMAND_MIDI_SILENCE)
      );
end;

{ FCN_NoteReset }

procedure FCN_NoteReset.SimpleFunction;
begin
  Args.Close;
  Result := TAlgosimSuccessIndication.CreateWithValue(
      Context.Perform(CLIENT_COMMAND_MIDI_RESET)
    );
end;

{ FCN_InstrumentInfo }

procedure FCN_InstrumentInfo.SimpleFunction;
var
  Obj: TAlgosimObject;
  Instrument: TMIDIInstrument;
begin
  Args.Extract(Obj).Close;
  Instrument := __InstrumentFromObj(Obj);
  with GetMIDIInstrumentData(Instrument) do
    Result := ASO
      (
        [
          sm('InstrumentFamily', ASO(InstrumentFamily)),
          sm('InstrumentName', ASO(InstrumentName)),
          sm('IsPercussionChannel', ASO(IsPercussionChannel)),
          sm('ProgramNumber', ASOInt(ProgramNumber))
        ]
      );
end;

{ FCN_PInstrumentInfo }

procedure FCN_PInstrumentInfo.SimpleFunction;
var
  Obj: TAlgosimObject;
  Instrument: TMIDIPercussionKey;
begin
  Args.Extract(Obj).Close;
  Instrument := __PercussionKeyFromObj(Obj);
  with GetMIDIPercussionInstrumentData(Instrument) do
    Result := ASO
      (
        [
          sm('InstrumentFamily', ASO(InstrumentFamily)),
          sm('InstrumentName', ASO(InstrumentName)),
          sm('IsPercussionChannel', ASO(IsPercussionChannel)),
          sm('NoteNumber', ASOInt(NoteNumber))
        ]
      );
end;

{ FCN_NoteName }

procedure FCN_NoteName.SimpleFunction;
var
  Note: Integer;
begin
  Args.ExtractNonNeg(Note).Close;
  if InRange(Note, Low(TMIDIInt), High(TMIDIInt)) then
    Result := ASO(MIDI_NOTE_NAMES[TMIDIInt(Note)])
  else
    ErrInvalidArguments;
end;

{ FCN_MidiMsg }

procedure FCN_MidiMsg.SimpleFunction;
var
  Msg: Int64;
begin
  Args.ExtractNonNeg(Msg).Close;
  if InRange(Msg, Cardinal.MinValue, Cardinal.MaxValue) then
    Result := TAlgosimSuccessIndication.CreateWithValue(
        Context.Perform(CLIENT_COMMAND_MIDI_MESSAGE, Msg)
      )
  else
    ErrInvalidArguments;
end;

{ FCN_LabelList }

procedure FCN_LabelList.SimpleFunction;
var
  Arr: TAlgosimArray;
  Labels: TArray<string>;
begin
  Labels := Args.Extract(Arr).ExtractStrings;
  Arr.OwnsObjects := False;
  Result := TAlgosimStructure.CreateWithValue(Labels, Arr.AsArray);
  Arr.Clear; // for additional safety
end;

{ TSymbolNameFcn }

procedure TSymbolNameFcn.DoExecute;
var
  SymbolName: string;
begin
  CheckNumArgs(1);
  if IsSymbol(Children[0]) then
    fcn(TASSymbolExprNode(Children[0]).Symbol)
  else
  begin
    if not EvalChildren then Exit;
    Args.Extract(SymbolName).Close;
    fcn(SymbolName);
  end;
end;

{ FCN_VarAppend }

procedure FCN_VarAppend.DoExecute;
var
  Obj, NewElement: TAlgosimObject;
begin
  CheckNumArgs(2);
  Obj := ExtractStoreRef(0);
  if not EvalChild(1) then Exit;
  Args.Skip.Extract(NewElement).Close;
  Children[1].Value := nil;
  Obj.Append(NewElement);
  Result := ASO(success);
end;

{ FCN_VarExtendWith }

procedure FCN_VarExtendWith.DoExecute;
var
  Obj, AugObj: TAlgosimObject;
begin
  CheckNumArgs(2);
  Obj := ExtractStoreRef(0);
  if not EvalChild(1) then Exit;
  Args.Skip.Extract(AugObj).Close;
  Children[1].Value := nil;
  Obj.ExtendWith(AugObj);
  Result := ASO(success);
end;

{ FCN_Catenate }

procedure FCN_Catenate.SimpleFunction;
var
  Objs: TArray<TAlgosimObject>;
  StrObjs: TArray<TAlgosimString>;
  VectObjs: TArray<TAlgosimVector>;
  ArrObjs: TArray<TAlgosimArray>;
  i: Integer;
begin

  CheckNumArgsAtLeast(1);

  SetLength(Objs, Args.Count);
  for i := 0 to Args.Count - 1 do
    Objs[i] := Children[i].Value;

  if TASOArrSpec.TrySpec<TAlgosimString>(Objs, StrObjs) then
    Result := TAlgosimString.Concat(StrObjs)
  else if TASOArrSpec.TrySpec<TAlgosimVector>(Objs, VectObjs) then
    Result := TAlgosimVector.Concat(VectObjs)
  else if TASOArrSpec.TrySpec<TAlgosimArray>(Objs, ArrObjs) then
    Result := TAlgosimArray.Concat(ArrObjs)
  else
    ErrInvalidArguments;

end;

{ FCN_VarInsert }

procedure FCN_VarInsert.DoExecute;
var
  Obj, NewElement: TAlgosimObject;
  Index: Integer;
begin
  CheckNumArgs(3);
  Obj := ExtractStoreRef(0);
  if not EvalChildren(1) then Exit;
  Args.Skip.Extract(Index).Extract(NewElement).Close;
  Children[2].Value := nil;
  Obj.Insert(Index, NewElement);
  Result := ASO(success);
end;

{ FCN_VarRemove }

procedure FCN_VarRemove.DoExecute;
var
  Obj: TAlgosimObject;
  Range: TArray<TRange>;
begin
  CheckNumArgs(2);
  Obj := ExtractStoreRef(0);
  if not EvalChild(1) then Exit;
  Args.Skip.Extract(Range).Close;
  Obj.Remove(Range);
  Result := ASO(success);
end;

{ FCN_VarTruncate }

procedure FCN_VarTruncate.DoExecute;
var
  Obj: TAlgosimObject;
  NewLength: Integer;
begin
  CheckNumArgs(2);
  Obj := ExtractStoreRef(0);
  if not EvalChild(1) then Exit;
  Args.Skip.Extract(NewLength).Close;
  Obj.Truncate(NewLength);
  Result := ASO(success);
end;

{ FCN_VarSwap }

procedure FCN_VarSwap.DoExecute;
var
  Obj: TAlgosimObject;
  Idx1, Idx2: Integer;
begin
  CheckNumArgs(3);
  Obj := ExtractStoreRef(0);
  if not EvalChildren(1) then Exit;
  Args.Skip.Extract(Idx1).Extract(Idx2).Close;
  Obj.Swap(Idx1, Idx2);
  Result := ASO(success);
end;

{ FCN_Numbers }

procedure FCN_Numbers.DoExecute;
var
  Arg: TAlgosimObject;
begin
  CheckNumArgs(1);
  if not ExtractRef(0, Arg) then Exit;
  Result := Arg.GetNumbers;
end;

{ FCN_CreateFunction }

procedure FCN_CreateFunction.DoExecute;
var
  SymbolRoot, ExprRoot: TASExprNode;
  Symbols: TArray<string>;
  i: Integer;
  FO: TCustomFunctionObj;
  ArgList: TList<TASExprNode>;
begin

  CheckNumArgs(2);
  SymbolRoot := Children[0];
  ExprRoot := Children[1];

  if IsSymbol(SymbolRoot) then
    Symbols := [TASSymbolExprNode(SymbolRoot).Symbol]
  else if IsBifurcation(SymbolRoot) then
  begin
    SetLength(Symbols, SymbolRoot.ChildCount);
    for i := 0 to SymbolRoot.ChildCount - 1 do
    begin
      if IsSymbol(SymbolRoot.Children[i]) then
        Symbols[i] := TASSymbolExprNode(SymbolRoot.Children[i]).Symbol
      else
        raise EInvArgs.CreateFmt(SASymbolWasExpected, [i + 1]);
    end;
  end;

  for i := 0 to High(Symbols) do
    if not IsValidIdent(Symbols[i]) then
      raise EInvalidIdentName.CreateFmt(SInvalidIdentName, [Symbols[i]]);

  FO := TCustomFunctionObj.Create;
  Value := FO; {noexcept, transfer of ownership}

  FO.Expression := ExprRoot.ExpressionRootedHere;
  SetLength(FO.Arguments, Length(Symbols));

  ArgList := TList<TASExprNode>.Create;
  try
    for i := 0 to High(Symbols) do
    begin
      ArgList.Clear;
      FindSymbols(FO.Expression.Root, Symbols[i], ArgList);
      FO.Arguments[i] := ArgList.ToArray;
    end;
  finally
    ArgList.Free;
  end;

end;

{ FCN_Image }

procedure FCN_Image.SimpleFunction;
var
  Fcn: TAlgosimFunctionObject;
  FcnArgs: TArray<TAlgosimObject>;
  Args: TArgumentExtractor;
  FcnArg: TAlgosimObject;
begin
  Self.Args.Extract(Fcn);
  Args := Self.Args(1);
  while Args.ArgExists do
  begin
    Args := Args.MoveObject(FcnArg);
    TArrBuilder<TAlgosimObject>.Add(FcnArgs, FcnArg); {noexcept}
  end;
  Result := Fcn.Execute(Context, FcnArgs, True);
end;

procedure FCN_IteratedImage.SimpleFunction;
var
  Fcn: TAlgosimFunctionObject;
  Arg: TAlgosimObject;
  N: Integer;
  i: Integer;
begin
  Arg := nil;
  try
    Args.Extract(Fcn).MoveObject(Arg).ExtractNonNeg(N).Close;
  except
    FreeAndNil(Arg);
    raise;
  end;
  for i := 1 to N do
    Arg := Fcn.Execute(Context, [Arg], True);
  Result := Arg;
end;

{ FCN_IteratedImages }

procedure FCN_IteratedImages.InitNode;
begin
  inherited;
  FContainerClass := TAlgosimArray;
end;

procedure FCN_IteratedImages.SimpleFunction;
var
  Fcn: TAlgosimFunctionObject;
  Arg: TAlgosimObject;
  Cur: TAlgosimObject;
  N: Integer;
  i: Integer;
begin
  Result := FContainerClass.Create;
  if Result is TAlgosimSet then
    Args.Extract(Fcn).Extract(Arg).ExtractNonNeg(N, Integer.MaxValue).Close
  else
    Args.Extract(Fcn).Extract(Arg).ExtractNonNeg(N).Close;
  if N <> Integer.MaxValue then
    Result.Capacity := N + 1;
  Result.AddElement(Arg.Clone);
  Cur := Arg.Clone;
  try
    for i := 1 to N do
    begin
      TObjReplacer<TAlgosimObject>.Replace(Cur, Fcn.Execute(Context, [Cur], False));
      if not Result.AddElement(Cur.Clone) then
        Break;
    end;
  finally
    Cur.Free;
  end;
end;

{ FCN_Orbit }

procedure FCN_Orbit.InitNode;
begin
  inherited;
  FContainerClass := TAlgosimSet;
end;

{ FCN_IsNumber }

procedure FCN_IsNumber.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(Obj is TAlgosimNumber);
end;

{ FCN_IsVector }

procedure FCN_IsVector.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(Obj is TAlgosimVector);
end;

{ FCN_IsMatrix }

procedure FCN_IsMatrix.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(Obj is TAlgosimMatrix);
end;

{ FCN_IsText }

procedure FCN_IsText.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(Obj is TAlgosimString);
end;

{ FCN_IsBoolean }

procedure FCN_IsBoolean.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(Obj is TAlgosimBoolean);
end;

{ FCN_IsPixmap }

procedure FCN_IsPixmap.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(Obj is TAlgosimPixmap);
end;

{ FCN_IsSound }

procedure FCN_IsSound.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(Obj is TAlgosimSound);
end;

{ FCN_IsTable }

procedure FCN_IsTable.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(Obj is TAlgosimTable);
end;

{ FCN_IsColor }

procedure FCN_IsColor.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(Obj is TAlgosimColor);
end;

{ FCN_IsSet }

procedure FCN_IsSet.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(Obj is TAlgosimSet);
end;

{ FCN_IsList }

procedure FCN_IsList.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(Obj is TAlgosimArray);
end;

{ FCN_IsStructure }

procedure FCN_IsStructure.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(Obj is TAlgosimStructure);
end;

{ FCN_IsReal }

procedure FCN_IsReal.SimpleFunction;
var
  Obj: TAlgosimNumericEntity;
begin
  Args.Extract(Obj).Close;
  with Obj.ImaginaryPart do
    try
      Result := ASO(IsZero)
    finally
      Free;
    end;
end;

{ FCN_IsComplex }

procedure FCN_IsComplex.SimpleFunction;
var
  Obj: TAlgosimNumericEntity;
begin
  Args.Extract(Obj).Close;
  with Obj.ImaginaryPart do
    try
      Result := ASO(IsNonZero)
    finally
      Free;
    end;
end;

{ FCN_IsInteger }

procedure FCN_IsInteger.SimpleFunction;
var
  Arg: TAlgosimObject;
begin
  Args.Extract(Arg).Close;
  Result := ASO((Arg is TAlgosimNumber) and Arg.IsASI);
end;

{ FCN_IsNumericEntity }

procedure FCN_IsNumericEntity.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(Obj is TAlgosimNumericEntity);
end;

{ FCN_IsNumericArray }

procedure FCN_IsNumericArray.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(Obj is TAlgosimNumericArray);
end;

{ FCN_IsBinaryData }

procedure FCN_IsBinaryData.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(Obj is TAlgosimBinaryData);
end;

{ FCN_entrywise }

procedure FCN_entrywise.SimpleFunction;
resourcestring
  SCannotComputeEntrywiseInEmptyList = 'Cannot compute entrywise images in an empty list of vectors or matrices.';
  SCannotComputeEntrywiseNonEqualSizes = 'Cannot compute entrywise images in a list of vectors or matrices of different sizes.';
var
  List: TAlgosimArray;
  Fcn: TAlgosimFunctionObject;
  HasMatrix, HasComplex: Boolean;
  Size: TSize;
  i: Integer;
  y: Integer;
  x: Integer;
  P: TPoint;
  EntrywiseList: TAlgosimArray;
  Entry: TAlgosimObject;
begin

  Args.Extract(List, restr, TAlgosimNumericArray).Extract(Fcn).Close;
  if List.ElementCount = 0 then
    raise EInvArgs.Create(SCannotComputeEntrywiseInEmptyList);
  HasComplex := List.IsComplex;
  HasMatrix := List.HasElementOfClass(TAlgosimMatrix);
  Size := List[1].PlanarExtent;
  for i := 2 to List.ElementCount do
    if List[i].PlanarExtent <> Size then
      raise EInvArgs.Create(SCannotComputeEntrywiseNonEqualSizes);

  Result := NumArrayClass(HasMatrix, HasComplex).Create;
  Result.PlanarExtent := Size;

  for y := 1 to Size.Height do
    for x := 1 to Size.Width do
    begin
      P := Point(x, y);
      EntrywiseList := TAlgosimArray.Create;
      try
        EntrywiseList.Capacity := List.ElementCount;
        for i := 1 to List.ElementCount do
          EntrywiseList.Add(List[i].ValueFromPoint[P]); {creating, immediately transferring ownership}
        Entry := Fcn.Execute(Context, [EntrywiseList], False); {creating}
        if Entry.IsComplex and not Result.IsComplex then {noexcept}
          try
            MakeComplex(Value);
          except
            Entry.Free;
            raise;
          end;
        Result.ValueFromPoint[P] := Entry; {transferring ownership}
      finally
        EntrywiseList.Free;
      end;
    end;

end;

{ FCN_Accumulate }

procedure FCN_Accumulate.SimpleFunction;
var
  Obj, InitialValue: TAlgosimObject;
  Fcn: TAlgosimFunctionObject;
begin
  Args.Extract(Obj).Extract(InitialValue).Extract(Fcn).Close;
  Result := Obj.Accumulate(InitialValue,
    function(CurVal, NewVal: TAlgosimObject): TAlgosimObject
    begin
      Result := Fcn.Execute(Context, [CurVal, NewVal], False);
    end
  );
end;

{ FCN_AccumulateList }

procedure FCN_AccumulateList.SimpleFunction;
var
  Obj, InitialValue: TAlgosimObject;
  Fcn: TAlgosimFunctionObject;
begin
  Args.Extract(Obj).Extract(InitialValue).Extract(Fcn).Close;
  Result := Obj.AccumulateStepsList(InitialValue,
    function(CurVal, NewVal: TAlgosimObject): TAlgosimObject
    begin
      Result := Fcn.Execute(Context, [CurVal, NewVal], False);
    end
  );
end;

{ FCN_AccumulateSteps }

procedure FCN_AccumulateSteps.SimpleFunction;
var
  Obj, InitialValue: TAlgosimObject;
  Fcn: TAlgosimFunctionObject;
begin
  Args.Extract(Obj).Extract(InitialValue).Extract(Fcn).Close;
  Result := Obj.AccumulateSteps(InitialValue,
    function(CurVal, NewVal: TAlgosimObject): TAlgosimObject
    begin
      Result := Fcn.Execute(Context, [CurVal, NewVal], False);
    end
  );
end;

{ FCN_Rest }

procedure FCN_Rest.SimpleFunction;
begin
  Args.MoveObject(Value).Close;
  Value.RemoveFirst;
end;

{ FCN_Append }

procedure FCN_Append.SimpleFunction;
var
  NewElement: TAlgosimObject;
begin
  Args.MoveObject(Value).Extract(NewElement).Close;
  Children[1].Value := nil; // Cannot be removed and the corresponding Extract replaced by MoveObject. Reason: Close might raise.
  Value.Append(NewElement);
end;

{ FCN_ExtendWith }

procedure FCN_ExtendWith.SimpleFunction;
var
  AugObj: TAlgosimObject;
begin
  Args.MoveObject(Value).Extract(AugObj).Close;
  Children[1].Value := nil; // Cannot be removed and the corresponding Extract replaced by MoveObject. Reason: Close might raise.
  Value.ExtendWith(AugObj);
end;

{ FCN_Insert }

procedure FCN_Insert.SimpleFunction;
var
  NewElement: TAlgosimObject;
  Index: Integer;
begin
  Args.MoveObject(Value).Extract(Index).Extract(NewElement).Close;
  Children[2].Value := nil; // Cannot be removed and the corresponding Extract replaced by MoveObject. Reason: Close might raise.
  Value.Insert(Index, NewElement);
end;

{ FCN_Remove }

procedure FCN_Remove.SimpleFunction;
var
  Range: TArray<TRange>;
begin
  Args.MoveObject(Value).Extract(Range).Close;
  Value.Remove(Range);
end;

{ FCN_Truncate }

procedure FCN_Truncate.SimpleFunction;
var
  NewLength: Integer;
begin
  Args.MoveObject(Value).Extract(NewLength).Close;
  Value.Truncate(NewLength);
end;

{ FCN_Swap }

procedure FCN_Swap.SimpleFunction;
var
  Idx1, Idx2: Integer;
begin
  Args.MoveObject(Value).Extract(Idx1).Extract(Idx2).Close;
  Value.Swap(Idx1, Idx2);
end;

{ FCN_SortBy }

procedure FCN_SortBy.SimpleFunction;
var
  Fcn: TAlgosimFunctionObject;
  Arr: TAlgosimArray;
  Imgs: TObjectDictionary<TAlgosimObject, TAlgosimObject>;
  i: Integer;
begin
  Args.MoveObject(Value).Extract(Fcn).Close;
  if Value is TAlgosimArray then
    Arr := TAlgosimArray(Value)
  else
    Arr := Value.ToList;
  try
    Imgs := TObjectDictionary<TAlgosimObject, TAlgosimObject>.Create([doOwnsValues],
      Arr.ElementCount, TAlgosimObject.RefEqualityComparer);
    try
      for i := 1 to Arr.ElementCount do
        Imgs.Add(Arr.Elements[i], Fcn.Execute(Context, [Arr.Elements[i]], False));
      Arr.Sort(
        TComparer<TAlgosimObject>.Construct(
          function(const Left, Right: TAlgosimObject): Integer
          begin
            Result := CompareASO(Imgs[Left], Imgs[Right]);
          end
        )
      );
    finally
      Imgs.Free;
    end;
    if not (Value is TAlgosimArray) then
      TObjReplacer<TAlgosimObject>.Replace(Value, Value.WithSpecificValues(Arr));
  finally
    if not (Value is TAlgosimArray) then
      Arr.Free;
  end;
end;

{ FCN_Member }

procedure FCN_Member.SimpleFunction;
var
  Struct: TAlgosimStructure;
  MemberName: string;
  FO: TCustomFunctionObj;
begin
  CheckNumArgs([1, 2]);
  case Args.Count of
    1:
      begin
        Args.Extract(MemberName).Close;
        Result := TCustomFunctionObj.Create;
        FO := TCustomFunctionObj(Result);
        FO.Expression := TASExpression.Create(FCN_Member);
        FO.Expression.Root.AddChild(TASSymbolExprNode);
        SetLength(FO.Arguments, 1);
        FO.Arguments[0] := [FO.Expression.Root.Children[0]];
        FO.Expression.Root.AddChild(ASO(MemberName));
      end;
    2:
      begin
        Args.Extract(Struct).Extract(MemberName).Close;
        Result := Struct.Values[MemberName];
        Struct.Release(MemberName);
      end;
  else
    ErrInvalidArguments;
  end;
end;

{ FCN_GroupBy }

procedure FCN_GroupBy.SimpleFunction;
var
  Obj, PrevObj: TAlgosimObject;
  Fcn: TAlgosimFunctionObject;
  Arr: TAlgosimArray;
  UseStruct: Boolean;
  Imgs: TObjectDictionary<TAlgosimObject, TAlgosimObject>;
  GroupStruct: TAlgosimStructure;
  Group: TAlgosimArray;
  TagLabel, ListLabel: string;
  i: Integer;
begin
  Args.Extract(Obj).Extract(Fcn).Extract(TagLabel, #0).Extract(ListLabel, 'members').Close;
  UseStruct := TagLabel <> #0;
  if Obj is TAlgosimArray then
    Arr := TAlgosimArray(Obj)
  else
    Arr := Obj.ToList;
  try
    Imgs := TObjectDictionary<TAlgosimObject, TAlgosimObject>.Create([doOwnsValues],
      Arr.ElementCount, TAlgosimObject.RefEqualityComparer);
    try
      for i := 1 to Arr.ElementCount do
        Imgs.Add(Arr.Elements[i], Fcn.Execute(Context, [Arr.Elements[i]], False));
      Arr.Sort(
        TComparer<TAlgosimObject>.Construct(
          function(const Left, Right: TAlgosimObject): Integer
          begin
            Result := CompareASO(Imgs[Left], Imgs[Right]);
          end
        )
      );
      Group := nil;
      PrevObj := nil;
      Result := TAlgosimArray.Create;
      for i := 1 to Arr.ElementCount do
      begin
        if (i = 1) or not SameASO(Imgs[PrevObj], Imgs[Arr.Elements[i]]) then
        begin
          if UseStruct then
          begin
            GroupStruct := TAlgosimStructure.Create;
            Result.AddElement(GroupStruct);
            GroupStruct.Add(TagLabel, Imgs[Arr.Elements[i]].Clone);
            Group := TAlgosimArray.Create;
            GroupStruct.Add(ListLabel, Group);
          end
          else
          begin
            Group := TAlgosimArray.Create;
            Result.AddElement(Group);
          end;
        end;
        PrevObj := Arr.Release(i);
        Group.AddElement(PrevObj); // transfer of ownership
      end;
    finally
      Imgs.Free;
    end;
  finally
    if not (Obj is TAlgosimArray) then
      Arr.Free;
  end;
end;

{ FCN_Characters }

procedure FCN_Characters.SimpleFunction;
var
  S: string;
begin
  Args.Extract(S).Close;
  Result := TAlgosimArray.CreateWithValue(S.ToCharArray);
end;

{ FCN_Words }

procedure FCN_Words.SimpleFunction;
resourcestring
  SInvWordExtractionPreset = 'Invalid word-extraction preset "%s".';
var
  S, Preset: string;
  Options: TAlgosimStructure;
  WEOptions: TWordExtractionOptions;
begin
  CheckNumArgs([1, 2]);
  Args.Extract(S);
  if Args.Count = 1 then
    Result := TAlgosimArray.CreateWithValue(ASStrFcns.GetWords(S, WEO_ENGLISH))
  else
    if Args.PeekAt(1) is TAlgosimString then
    begin
      Args(1).Extract(Preset).Close;
      if SameText(Preset, 'English') then
        Result := TAlgosimArray.CreateWithValue(ASStrFcns.GetWords(S, WEO_ENGLISH))
      else if SameText(Preset, 'Math') then
        Result := TAlgosimArray.CreateWithValue(ASStrFcns.GetWords(S, WEO_ENGLISH_MATH))
      else if SameText(Preset, 'Source code') then
        Result := TAlgosimArray.CreateWithValue(ASStrFcns.GetWords(S, WEO_ENGLISH_SOURCECODE))
      else
        raise EInvArgs.CreateFmt(SInvWordExtractionPreset, [Preset]);
    end
    else
    begin
      Args(1).Extract(Options).Close;
      WEOptions := WEO_ENGLISH;
      if Options.HasMember('WordSeps') then
        WEOptions.WordSeps := Options['WordSeps'].ToString;
      if Options.HasMember('MathSeps') then
        WEOptions.MathSeps := Options['MathSeps'].ToBoolean;
      if Options.HasMember('TrimChrs') then
        WEOptions.TrimChrs := Options['TrimChrs'].ToString;
      if Options.HasMember('TrimPunct') then
        WEOptions.TrimPunct := Options['TrimPunct'].ToBoolean;
      if Options.HasMember('LetterRequired') then
        WEOptions.LetterRequired := Options['LetterRequired'].ToBoolean;
      if Options.HasMember('LetterOrDigitRequired') then
        WEOptions.LetterOrDigitRequired := Options['LetterOrDigitRequired'].ToBoolean;
      Result := TAlgosimArray.CreateWithValue(ASStrFcns.GetWords(S, WEOptions));
    end;
end;

{ FCN_Do }

procedure FCN_Do.SimpleFunction;
begin
  if Args.Count > 0 then
    Args(Args.Count - 1).MoveObject(Value)
  else
    Value := ASO(null);
end;

{ FCN_Divides }

procedure FCN_Divides.SimpleFunction;
var
  a, b: TASI;
begin
  Args.Extract(a).Extract(b).Close;
  Result := ASO(b mod a = 0);
end;

{ FCN_NotDivides }

procedure FCN_NotDivides.SimpleFunction;
var
  a, b: TASI;
begin
  Args.Extract(a).Extract(b).Close;
  Result := ASO(b mod a <> 0);
end;

{ FCN_Primorial }

procedure FCN_Primorial.SimpleFunction;
var
  n: TASI;
begin
  Args.ExtractNonNeg(n).Close;
  if n < 0 then
    Result := ASOInt(1)
  else if InRange(n, Low(IntPrimorials), High(IntPrimorials)) then
    Result := ASOInt(IntPrimorials[n])
  else
    Result := ASO(Primorial(n));
end;

{ FCN_Inc }

procedure FCN_Inc.DoExecute;
var
  Num: TAlgosimNumber;
  N: TASI;
begin
  CheckNumArgs([1, 2]);
  Num := ExtractStoreRef<TAlgosimNumber>(0);
  case Args.Count of
    1:
      Num.Increase;
    2:
      begin
        if not EvalChild(1) then Exit;
        Args(1).Extract(N);
        Num.Increase(N);
      end
  else
    ErrInvalidArguments;
  end;
  Result := Num.Clone;
end;

{ FCN_Dec }

procedure FCN_Dec.DoExecute;
var
  Num: TAlgosimNumber;
  N: TASI;
begin
  CheckNumArgs([1, 2]);
  Num := ExtractStoreRef<TAlgosimNumber>(0);
  case Args.Count of
    1:
      Num.Increase(-1);
    2:
      begin
        if not EvalChild(1) then Exit;
        Args(1).Extract(N);
        Num.Increase(-N);
      end
  else
    ErrInvalidArguments;
  end;
  Result := Num.Clone;
end;

{ FCN_Variables }

procedure FCN_Variables.SimpleFunction;
begin
  Args.Close;
  Result := TAlgosimArray.CreateWithValue(Context.GetVariableList);
end;

{ FCN_LastError }

procedure FCN_LastError.SimpleFunction;
begin
  Args.Close;
  Result := Context.GetLastError;
end;

{ FCN_Functions }

procedure FCN_Functions.SimpleFunction;
begin
  Args.Close;
  Result := TAlgosimArray.CreateWithValue(Context.GetFunctionList);
end;

{ TKernelFunctionFcn }

procedure TKernelFunctionFcn.SimpleFunction;
var
  FO: TKernelFunctionObj;
  FcnName: string;
  FcnClass: TASFunctionClass;
begin

  if Args.PeekAt(0) is TAlgosimFunctionObject then
  begin
    Args.Extract(FO).Close;
    FcnClass := FO.FuncClass;
  end
  else
  begin
    Args.Extract(FcnName).Close;
    if not TFunctionMgr.Functions.TryGetValue(FcnName, FcnClass) then
      raise EUnknownIdentifier.CreateFmt(SUnknownIdentifier, [FcnName]);
  end;

  Fcn(FcnClass);

end;

{ FCN_Function }

procedure FCN_Function.Fcn(AFcnClass: TASFunctionClass);
begin
  Result := TKernelFunctionObj.Create(AFcnClass);
end;

{ FCN_Categories }

procedure FCN_Categories.Fcn(AFcnClass: TASFunctionClass);
var
  FcnCats: TArray<TFcnCategory>;
  CatNames: TArray<string>;
  i: Integer;
begin

  if TFunctionMgr.Categories.TryGetValue(AFcnClass, FcnCats) then
  begin
    SetLength(CatNames, Length(FcnCats));
    for i := 0 to High(CatNames) do
      CatNames[i] := FcnCats[i].ToString;
    Result := TAlgosimArray.CreateWithValue(CatNames)
  end
  else
    Result := ASO(null);

end;

{ FCN_FcnName }

procedure FCN_FcnName.Fcn(AFcnClass: TASFunctionClass);
var
  FcnNames: TArray<string>;
begin

  if TFunctionMgr.Names.TryGetValue(AFcnClass, FcnNames) and (Length(FcnNames) > 0) then
    Result := ASO(FcnNames[0])
  else
    Result := ASO(null);

end;

{ FCN_FcnNames }

procedure FCN_FcnNames.Fcn(AFcnClass: TASFunctionClass);
var
  FcnNames: TArray<string>;
begin

  if TFunctionMgr.Names.TryGetValue(AFcnClass, FcnNames) then
    Result := TAlgosimArray.CreateWithValue(FcnNames)
  else
    Result := ASO(null);

end;

{ FCN_ErrorInfo }

procedure FCN_ErrorInfo.DoExecute;
var
  Err: TAlgosimFailure;
begin
  CheckNumArgs(1);
  Children[0].Evaluate;
  if IsFailure(Children[0].Value) then
  begin
    Err := TAlgosimFailure(Children[0].Value);
    Result := ASOErrorInfo(Err.FailureReason, Err.Source.ToArray);
  end
  else
    Result := ASO(null);
end;

{ FCN_Succ }

procedure FCN_Succ.SimpleFunction;
var
  n, m, d: TASI;
begin
  CheckNumArgs([1, 2, 3]);
  case Args.Count of
    1:
      begin
        Args.Extract(n).Close;
        Result := ASOInt(Succ(n));
      end;
    2:
      begin
        Args.Extract(n).ExtractPos(m).Close;
        Result := ASOInt(imod(Succ(n), m));
      end;
    3:
      begin
        Args.Extract(n).ExtractPos(m).Extract(d).Close;
        Result := ASOInt(d + imod(Succ(n - d), m));
      end;
  else
    ErrInvalidArguments;
  end;
end;

{ FCN_Pred }

procedure FCN_Pred.SimpleFunction;
var
  n, m, d: TASI;
begin
  CheckNumArgs([1, 2, 3]);
  case Args.Count of
    1:
      begin
        Args.Extract(n).Close;
        Result := ASOInt(Pred(n));
      end;
    2:
      begin
        Args.Extract(n).ExtractPos(m).Close;
        Result := ASOInt(imod(Pred(n), m));
      end;
    3:
      begin
        Args.Extract(n).ExtractPos(m).Extract(d).Close;
        Result := ASOInt(d + imod(Pred(n - d), m));
      end;
  else
    ErrInvalidArguments;
  end;
end;

{ FCN_LoadDefVars }

procedure FCN_LoadDefVars.SimpleFunction;
begin
  Args.Close;
  Context.LoadDefVars;
  Result := ASO(success);
end;

{ FCN_Operators }

procedure FCN_Operators.SimpleFunction;
begin
  Args.Close;
  Result := Context.GetOperatorList;
end;

{ FCN_If }

procedure FCN_If.DoExecute;
var
  b: Boolean;
begin
  CheckNumArgs([2, 3]);
  if not EvalChild(0) then Exit;
  Args.Extract(b);
  if b then
  begin
    if not EvalChild(1) then Exit;
    TMover<TAlgosimObject>.Move(Value, Children[1].Value);
  end
  else if Args.Count = 3 then
  begin
    if not EvalChild(2) then Exit;
    TMover<TAlgosimObject>.Move(Value, Children[2].Value);
  end;
end;

{ FCN_ForEach }

procedure FCN_ForEach.DoExecute;
const
  ARG_INDEX_OBJECT = 0;
  ARG_INDEX_SYMBOL = 1;
  ARG_INDEX_EXPRESSION = 2;
var
  Obj: TAlgosimObject;
  symbol: string;
  symbols: TList<TASExprNode>;
  i: Integer;
begin

  CheckNumArgs(3);
  if not ExtractRef<TAlgosimObject>(ARG_INDEX_OBJECT, Obj) then Exit;
  CheckSymbol(ARG_INDEX_SYMBOL);
  symbol := TASSymbolExprNode(Children[ARG_INDEX_SYMBOL]).Symbol;

  symbols := TList<TASExprNode>.Create;
  try

    FindSymbols(Children[ARG_INDEX_EXPRESSION], symbol, symbols);

    for i := 1 to Obj.ValueCount do
    begin
      PopulateSymbols(symbols, Obj.Values[i]);
      if not EvalChildCtrl(ARG_INDEX_EXPRESSION) then Exit;
    end;

  finally
    symbols.Free;
  end;

end;

{ FCN_Print }

procedure FCN_Print.SimpleFunction;
var
  BufName: string;
  Obj: TAlgosimObject;
  S: string;
begin
  CheckNumArgs([1, 2]);
  case Args.Count of
    1:
      begin
        Args.Extract(Obj).Close;
        S := Obj.ToString;
        Context.Perform(CLIENT_COMMAND_PRINT, 0, NativeInt(PChar(S)));
      end;
    2:
      begin
        Args.Extract(BufName).Extract(Obj).Close;
        S := Obj.ToString;
        Context.BufferAppend(BufName, S);
        Context.Perform(CLIENT_COMMAND_PRINT, NativeInt(PChar(BufName)), NativeInt(PChar(S)));
      end
  else
    ErrInvalidArguments;
  end;
end;

{ FCN_RemoveBuffer }

procedure FCN_RemoveBuffer.SimpleFunction;
var
  BufName: string;
begin
  Args.Extract(BufName).Close;
  Context.RemoveBuffer(BufName);
  Context.Perform(CLIENT_COMMAND_REMOVEBUFFER, NativeInt(PChar(BufName)));
end;

{ FCN_BufferText }

procedure FCN_BufferText.SimpleFunction;
var
  BufName: string;
begin
  Args.Extract(BufName).Close;
  Result := ASO(Context.GetBufferText(BufName));
end;

{ FCN_Buffers }

procedure FCN_Buffers.SimpleFunction;
begin
  Args.Close;
  Result := TAlgosimArray.CreateWithValue(Context.GetBuffers);
end;

{ FCN_MessageBox }

procedure FCN_MessageBox.SimpleFunction;
var
  Text: TAlgosimObject;
  Icon: string;
  Buttons: TAlgosimArray;
  DefBtn, CancelBtn: string;
  MsgBoxInfo: TMsgBoxInfo;
  DisplayCaptions: TArray<string>;
begin

  if Args.PeekAt(1) is TAlgosimString then
  begin
    Args
      .Extract(Text)
      .Extract(Icon)
      .Extract(Buttons, restr, TAlgosimString, defval, nil)
      .Extract(DefBtn, '')
      .Extract(CancelBtn, '')
      .Close;
  end
  else
  begin
    Args
      .Extract(Text)
      .Extract(Buttons, restr, TAlgosimString, defval, nil)
      .Extract(DefBtn, '')
      .Extract(CancelBtn, '')
      .Close;
  end;

  MsgBoxInfo := TMsgBoxInfo.Create;
  try
    MsgBoxInfo.Text := Text.GetAsMultiLineText(Context.FormatOptions);
    MsgBoxInfo.Icon := Icon;
    if Assigned(Buttons) and (Buttons.ElementCount > 0) then
      MsgBoxInfo.Buttons := Buttons.ToStringArray
    else
      MsgBoxInfo.Buttons := ['OK'];
    DisplayCaptions := MsgBoxInfo.DisplayCaptions;
    MsgBoxInfo.DefButton := IndexStr(DefBtn, DisplayCaptions);
    MsgBoxInfo.CancelButton := IndexStr(CancelBtn, DisplayCaptions);
    if
      Context.Perform(CLIENT_COMMAND_MSGBOX, NativeInt(MsgBoxInfo)) and
      InRange(MsgBoxInfo.Result, 0, High(MsgBoxInfo.Buttons))
    then
      Result := ASO(MsgBoxInfo.DisplayCaption(MsgBoxInfo.Result))
    else
      Result := ASO(failure)
  finally
    MsgBoxInfo.Free;
  end;

end;

{ FCN_InputBox }

procedure FCN_InputBox.SimpleFunction;
var
  Caption, DefVal: string;
  InputBoxInfo: TInputBoxInfo;
begin
  Args.Extract(Caption).Extract(DefVal, '').Close;
  InputBoxInfo := TInputBoxInfo.Create;
  try
    InputBoxInfo.Caption := Caption;
    InputBoxInfo.DefVal := DefVal;
    if Context.Perform(CLIENT_COMMAND_INPUTBOX, NativeInt(InputBoxInfo)) then
      if InputBoxInfo.Canceled then
        Result := ASO(failure, SUserCanceled)
      else
        Result := ASO(InputBoxInfo.OutText)
    else
      Result := ASO(failure);
  finally
    InputBoxInfo.Free;
  end;
end;

{ FCN_FormatDateTime }

procedure FCN_FormatDateTime.SimpleFunction;
var
  D: TDateTime;
  Fmt: string;
begin
  Args.Extract(D).Extract(Fmt, 'yyyy"-"mm"-"dd" "hh":"nn":"ss').Close;
  Result := ASO(FormatDateTime(Fmt, D, DefaultFormatSettings));
end;

{ FCN_DateTimeString }

procedure FCN_DateTimeString.SimpleFunction;
var
  D: TDateTime;
  LocID: string;
begin
  Args.Extract(D).Extract(LocID, '').Close;
  if LocID.IsEmpty then
    Result := ASO(DateTimeToStr(D, TFormatSettings.Create))
  else
    Result := ASO(DateTimeToStr(D, TFormatSettings.Create(LocID)))
end;

{ FCN_DateString }

procedure FCN_DateString.SimpleFunction;
var
  D: TDateTime;
  LocID: string;
begin
  Args.Extract(D).Extract(LocID, '').Close;
  if LocID.IsEmpty then
    Result := ASO(DateToStr(D, TFormatSettings.Create))
  else
    Result := ASO(DateToStr(D, TFormatSettings.Create(LocID)))
end;

{ FCN_TimeString }

procedure FCN_TimeString.SimpleFunction;
var
  D: TDateTime;
  LocID: string;
begin
  Args.Extract(D).Extract(LocID, '').Close;
  if LocID.IsEmpty then
    Result := ASO(TimeToStr(D, TFormatSettings.Create))
  else
    Result := ASO(TimeToStr(D, TFormatSettings.Create(LocID)))
end;

{ FCN_While }

procedure FCN_While.DoExecute;
const
  ARG_INDEX_CONDITION = 0;
  ARG_INDEX_BODY = 1;
begin

  CheckNumArgs(2);

  while
    EvalChild(ARG_INDEX_CONDITION) and
    Children[ARG_INDEX_CONDITION].Value.ToBoolean and
    EvalChildCtrl(ARG_INDEX_BODY)
  do
    QuitPauseCheck;

end;

{ FCN_Until }

procedure FCN_Until.DoExecute;
const
  ARG_INDEX_CONDITION = 1;
  ARG_INDEX_BODY = 0;
begin

  CheckNumArgs(2);

  repeat
    if not EvalChildCtrl(ARG_INDEX_BODY) then
      Break;
    QuitPauseCheck;
  until not EvalChild(ARG_INDEX_CONDITION) or Children[ARG_INDEX_CONDITION].Value.ToBoolean;

end;

{ FCN_Repeat }

procedure FCN_Repeat.DoExecute;
const
  ARG_INDEX_BODY = 0;
begin

  CheckNumArgs(1);

  while
    EvalChildCtrl(ARG_INDEX_BODY)
  do
    QuitPauseCheck;

end;

{ FCN_For }

procedure FCN_For.DoExecute;
const
  ARG_INDEX_SYMBOL = 0;
  ARG_INDEX_LOWER = 1;
  ARG_INDEX_UPPER = 2;
  ARG_INDEX_BODY = 3;
var
  symbol: string;
  symbols: TList<TASExprNode>;
  a, b: TASI;
  i: TASI;
begin

  CheckNumArgs(4);
  CheckSymbol(ARG_INDEX_SYMBOL);
  symbol := TASSymbolExprNode(Children[ARG_INDEX_SYMBOL]).Symbol;

  if not EvalChild(ARG_INDEX_LOWER) then Exit;
  if not EvalChild(ARG_INDEX_UPPER) then Exit;

  Args.Skip.Extract(a).Extract(b);

  symbols := TList<TASExprNode>.Create;
  try

    FindSymbols(Children[ARG_INDEX_BODY], symbol, symbols);

    for i := a to b do
    begin
      PopulateSymbols(symbols, ASOInt(i));
      if not EvalChildCtrl(ARG_INDEX_BODY) then Exit;
      QuitPauseCheck;
    end;

  finally
    symbols.Free;
  end;

end;

{ FCN_Tokenize }

procedure FCN_Tokenize.SimpleFunction;
var
  Expr: string;
  Tokens: TObjectList<TToken>;
  Strs: TList<string>;
  i: Integer;
begin
  Args.Extract(Expr).Close;
  Tokens := TTokenizer.Tokenize(Expr);
  try
    Strs := TList<string>.Create;
    try
      for i := 0 to Tokens.Count - 1 do
        Strs.Add(Tokens[i].ToString);
      Result := TAlgosimArray.CreateWithValue(Strs.ToArray);
    finally
      Strs.Free;
    end;
  finally
    Tokens.Free;
  end;
end;

{ FCN_Parse }

procedure FCN_Parse.SimpleFunction;
var
  Expr: string;
  Tokens: TObjectList<TToken>;
  AST: TASExpression;
begin
  Args.Extract(Expr).Close;
  Tokens := TTokenizer.Tokenize(Expr);
  try
    AST := TParser.Parse(Tokens);
    try
      Result := ASO(AST.Root.SubtreeAsString);
    finally
      AST.Free;
    end;
  finally
    Tokens.Free;
  end;
end;

{ FCN_WordWrap }

procedure FCN_WordWrap.SimpleFunction;
var
  Text: string;
  Width: Integer;
begin
  Args.Extract(Text).ExtractPos(Width, 80).Close;
  Result := ASO(WordWrap(Text, Width));
end;

{ FCN_History }

procedure FCN_History.SimpleFunction;
var
  Index: Integer;
  Item: TASKernel.TCmdHistoryItem;
begin
  Args.Extract(Index).Close;
  Item := Context.HistItem(Index);
  try
    Result := ASOCmdHistItem(Item.Cmd, Item.StartTime, Item.EvalTime, Item.Result);
    Item.Result := nil;
  finally
    Item.Free;
  end;
end;

{ FCN_Input }

procedure FCN_Input.SimpleFunction;
var
  Index: Integer;
  Item: TASKernel.TCmdHistoryItem;
begin
  Args.Extract(Index).Close;
  Item := Context.HistItemNoObj(Index);
  try
    Result := ASO(Item.Cmd);
  finally
    Item.Free;
  end;
end;

{ FCN_Inputs }

procedure FCN_Inputs.SimpleFunction;
var
  Item: TASKernel.TCmdHistoryItem;
  i: Integer;
  List: TArray<string>;
begin
  Args.Close;
  SetLength(List, Context.HistLength);
  for i := 0 to High(List) do
  begin
    Item := Context.HistItemNoObj(i + 1);
    try
      List[i] := Item.Cmd;
    finally
      Item.Free;
    end;
  end;
  Result := TAlgosimArray.CreateWithValue(List);
end;

{ FCN_Output }

procedure FCN_Output.SimpleFunction;
var
  Index: Integer;
  Item: TASKernel.TCmdHistoryItem;
begin
  Args.Extract(Index).Close;
  Item := Context.HistItem(Index);
  try
    TMover<TAlgosimObject>.Move(Value, Item.Result);
  finally
    Item.Free;
  end;
end;

{ FCN_HistoryLength }

procedure FCN_HistoryLength.SimpleFunction;
begin
  Args.Close;
  Result := ASOInt(Context.HistLength);
end;

{ FCN_ClearHistory }

procedure FCN_ClearHistory.SimpleFunction;
var
  Index: Integer;
begin
  if Args.Count = 0 then
    Context.ClearHistory
  else
  begin
    Args.Extract(Index).Close;
    Context.ClearHistoryRes(Index);
  end;
  Result := ASO(success);
end;

{ FCN_SaveHistory }

procedure FCN_SaveHistory.SimpleFunction;
var
  State: Boolean;
begin
  Args.Extract(State).Close;
  Context.SaveHistory(State);
end;

{ FCN_SelfTest }

procedure FCN_SelfTest.SimpleFunction;
begin
  var s := '';
  Args.Extract(s, '').Close;
  if s = 'graphics' then
    Context.Perform(CLIENT_COMMAND_GRPHTEST)
  else
    Context.Perform(CLIENT_COMMAND_SELFTEST);
end;

{ FCN_Bases }

procedure FCN_Bases.SimpleFunction;
var
  fo: TFormatOptions;
  bases: TArray<Int64>;
  pb: TNumberBases;
  i: Integer;
begin

  bases := Args.ExtractInt64s;
  pb := [];
  for i := 0 to High(bases) do
    if InRange(bases[i], Low(TNumberBase), High(TNumberBase)) then
      Include(pb, TNumberBase(bases[i]))
    else
      raise Exception.CreateFmt(SInvNumberBase, [bases[i]]);

  fo := Context.FormatOptions;
  fo.Numbers.PreferredBases := pb;
  Context.FormatOptions := fo;

end;

{ FCN_FcnExpr }

procedure FCN_FcnExpr.SimpleFunction;
var
  F: TCustomFunctionObj;
  &Strict: Boolean;
begin
  Args.Extract(F).Extract(&Strict, False).Close;
  Result := ASO(F.ExprAsStr(&Strict));
end;

{ FCN_RandomColor }

procedure FCN_RandomColor.SimpleFunction;
begin
  Args.Close;
  Result := ASO(TRGB.Create(Random, Random, Random));
end;

{ FCN_Compute }

procedure FCN_Compute.DoExecute;
type
  TIndexData = record
    Symbol: string;
    From,
    &To: Integer
  end;
var
  Args: TArgumentExtractor;
  IndexData: TIndexData;
  Indices: TArray<TIndexData>;
  i: TArray<Integer>;
  CurLists: TArray<TAlgosimArray>;
  ResultArray: TAlgosimArray;

  procedure NextElement;
  var
    p: Integer;

    procedure CreateNewLists(ARoot: TAlgosimArray);
    var
      pp: Integer;
    begin
      for pp := p to High(i) - 1 do
      begin
        CurLists[pp] := TAlgosimArray.Create;
        ARoot.Add(CurLists[pp]);
        ARoot := CurLists[pp];
      end;
    end;

  begin
    p := High(i);
    while p > 0 do
    begin
      if i[p] < Indices[p].&To then
      begin
        Inc(i[p]);
        CreateNewLists(CurLists[p - 1]);
        Exit;
      end
      else
        i[p] := Indices[p].From;
      Dec(p);
    end;
    if p = 0 then
    begin
      Inc(i[p]);
      if i[p] <= Indices[p].&To then
        CreateNewLists(ResultArray);
    end;
  end;

  function ElementExists: Boolean;
  begin
    Result := (Length(i) > 0) and (i[0] <= Indices[0].&To);
  end;

var
  ai: Integer;
  p: Integer;
  ElemCount: Integer;
  IterGuardCounter: Integer;
  l: TAlgosimArray;
  CurObj: TAlgosimObject;
  SymLists: TArray<TList<TASExprNode>>;

begin
  CheckNumArgsAtLeast(4);
  Args := Self.Args(1);
  ai := 1;
  ResultArray := TAlgosimArray.Create;
  Result := ResultArray;
  ElemCount := 1;
  while Args.ArgExists do
  begin
    CheckNumArgsAtLeast(ai + 3);
    if not EvalChild(ai + 1) or not EvalChild(ai + 2) then Exit;
    Args := Args
      .ExtractSymbol(IndexData.Symbol)
      .Extract(IndexData.From)
      .Extract(IndexData.&To);
    if IndexData.From > IndexData.&To then
      Exit;
    ElemCount := ElemCount * (IndexData.&To - IndexData.From + 1);
    TArrBuilder<TIndexData>.Add(Indices, IndexData);
    Inc(ai, 3);
  end;
  SetLength(i, Length(Indices));
  SetLength(CurLists, Length(Indices) - 1);
  SetLength(SymLists, Length(Indices));
  try
    l := ResultArray;
    for p := 0 to High(Indices) do
    begin
      SymLists[p] := TList<TASExprNode>.Create;
      FindSymbols(Children[0], Indices[p].Symbol, SymLists[p]);
      i[p] := Indices[p].From;
      if p < High(Indices) then
      begin
        CurLists[p] := TAlgosimArray.Create;
        l.Add(CurLists[p]);
        l := CurLists[p];
      end;
    end;
    IterGuardCounter := 0;
    while ElementExists do
    begin
      if IterGuardCounter = ElemCount then
        raise Exception.Create('Too many elements are attempted to be computed.');
      for p := 0 to High(Indices) do
        PopulateSymbols(SymLists[p], ASOInt(i[p]));
      Children[0].Evaluate;
      if IsControl(Children[0].Value) then
      begin
        FreeAndNil(Value);
        TMover<TAlgosimObject>.Move(Value, Children[0].Value);
        Exit;
      end;
      TMover<TAlgosimObject>.Move(CurObj, Children[0].Value);
      if Length(CurLists) > 0 then
        CurLists[High(CurLists)].Add(CurObj)
      else
        ResultArray.Add(CurObj);
      Inc(IterGuardCounter);
      NextElement;
    end;
    if IterGuardCounter < ElemCount then
      raise Exception.Create('Too few elements were computed.');
  finally
    for p := 0 to High(SymLists) do
      FreeAndNil(SymLists[p]);
  end;
end;

{ FCN_DebugObject }

procedure FCN_DebugObject.SimpleFunction;
var
  ObjName: string;
  bm: Graphics.TBitmap;
begin
  Args.Extract(ObjName).Close;
  if ObjName = 'empty vector' then
    Result := ASO(TRealVector.Create([]))
  else if ObjName = 'empty matrix' then
    Result := ASO(IdentityMatrix(0))
  else if ObjName = 'empty sound' then
    Result := ASO(SineTone(200, 0.1, 0.0))
  else if IndexText(ObjName, ['Sally', 'rabbit', 'harvestman']) <> -1 then
  begin
    bm := LoadResBitmap(ObjName);
    try
      bm.PixelFormat := pf32bit;
      Result := ASO(TASPixmap.Create(bm));
    finally
      bm.Free;
    end;
  end
  else if ObjName = 'success indication' then
    Result := ASO(success)
  else if ObjName = 'delay' then
    Sleep(10000)
  else if ObjName = 'exception masks' then
  begin
    var LExprThreadFPCW := Get8087CW;
    var LClientThreadFPCW: Word := 0;
    Context.Perform(CLIENT_COMMAND_GETFPCW, NativeInt(@LClientThreadFPCW));
    Result :=
      TAlgosimStructure.CreateWithValue(
        [
          sm('kernel', FPCWStructure(LExprThreadFPCW)),
          sm('client', FPCWStructure(LClientThreadFPCW))
        ]
      );
  end
  else if ObjName = 'restore exception masks' then
  begin
    Context.Perform(CLIENT_COMMAND_SETFPCW);
    if TThread.Current.ThreadID <> MainThreadID then
    begin
      var CW: Word := KernelFPUCW;
      asm
        FNCLEX
        FLDCW  CW
      end;
    end;
    Result := ASO(null);
  end
  else if ObjName = 'kernel exception' then
  begin
    raise EKernelException.Create('Kernel exception raised programmatically.');
  end
  else if ObjName = 'front-end exception' then
  begin
    Context.Perform(CLIENT_COMMAND_FRONTENDEXCEPTION, 0);
    Result := ASO(null);
  end
  else if ObjName = 'client exception' then
  begin
    Context.Perform(CLIENT_COMMAND_FRONTENDEXCEPTION, 1);
    Result := ASO(null);
  end
  else if ObjName = 'prototypes' then
    Result := TAlgosimArray.CreateWithValue(
      [
        ASOInt(0),
        ASORat(TRationalNumber.Create(0, 1)),
        ASO(TASR(0.0)),
        ASO(TASC(0.0)),
        ASO(ZeroVector(1)),
        ASO(ComplexZeroVector(1)),
        ASO(ZeroMatrix(1)),
        ASO(ComplexZeroMatrix(1)),
        ASO(False),
        ASOColor(clBlack),
        ASO(''),
        TAlgosimArray.Create,
        TAlgosimSet.Create,
        TAlgosimStructure.Create,
        ASO(TASPixmap.Create(1, 1)),
        ASO(TASSound.CreateUsingTime(CD_QUALITY_SAMPLE_RATE, 32, 1, KSAUDIO_SPEAKER_MONO, 0)),
        TAlgosimBinaryData.Create,
        ASO(TASTable.Create),
        ASO(null),
        ASO(success)
      ]
    )
  else if ObjName = 'rgl log' then
    rgl.rglEnableDebugLog
  else if ObjName = 'rgl ctx count' then
    Result := ASOInt(TRglContext.GlobalCount)
  else if ObjName = 'win32 handles' then
    Result := TAlgosimStructure.CreateWithValue(
      [
        sm('current',
        TAlgosimStructure.CreateWithValue(
          [
            sm('GDI', ASOInt(GetGuiResources(GetCurrentProcess, GR_GDIOBJECTS))),
            sm('user', ASOInt(GetGuiResources(GetCurrentProcess, GR_USEROBJECTS)))
          ]
        )),
        sm('peak',
        TAlgosimStructure.CreateWithValue(
          [
            sm('GDI', ASOInt(GetGuiResources(GetCurrentProcess, GR_GDIOBJECTS_PEAK))),
            sm('user', ASOInt(GetGuiResources(GetCurrentProcess, GR_USEROBJECTS_PEAK)))
          ]
        ))
      ]
    )
  else if ObjName = 'containers' then
  begin
    Context.Perform(CLIENT_COMMAND_UXPANELDEBUG, 1);
    Result := ASO(null);
  end
  else if ObjName = 'containers off' then
  begin
    Context.Perform(CLIENT_COMMAND_UXPANELDEBUG, 0);
    Result := ASO(null);
  end
  else if ObjName = 'ux objects' then
  begin
    var forms: Integer := -1;
    var stacks: Integer := -1;
    var panels: Integer := -1;
    if Context.Perform(CLIENT_COMMAND_UXOBJECTS, NativeInt(@forms), NativeInt(@stacks), NativeInt(@panels)) then
      Result := TAlgosimStructure.CreateWithValue(
        [
          sm('forms', ASOInt(forms)),
          sm('stacks', ASOInt(stacks)),
          sm('panels', ASOInt(panels))
        ]
      )
  end
  else if ObjName.StartsWith('log ', True) then
  begin
    var S := Copy(ObjName, 5);
    Context.Perform(CLIENT_COMMAND_DEBUGTEXT, NativeInt(PChar(s)));
    Result := ASO(null);
  end
  else if ObjName = 'clear log' then
  begin
    Context.Perform(CLIENT_COMMAND_DEBUGCLEAR);
    Result := ASO(null);
  end;
end;

{ FCN_CompareString }

procedure FCN_CompareString.SimpleFunction;
var
  L, R: string;
begin
  Args.Extract(L).Extract(R).Close;
  Result := ASOInt(CompareStr(L, R));
end;

{ FCN_IsCharacter }

procedure FCN_IsCharacter.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO((Obj is TAlgosimString) and (Obj.ValueCount = 1));
end;

{ FCN_IsRealType }

procedure FCN_IsRealType.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(not (asoComplex in Obj.ClassData.ClassFlags));
end;

{ FCN_IsComplexType }

procedure FCN_IsComplexType.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  Args.Extract(Obj).Close;
  Result := ASO(asoComplex in Obj.ClassData.ClassFlags);
end;

{ FCN_Break }

procedure FCN_Break.SimpleFunction;
var
  D: Integer;
begin
  Args.ExtractPos(D, 1).Close;
  Result := ASOBreak(D);
end;

{ FCN_Continue }

procedure FCN_Continue.SimpleFunction;
begin
  Args.Close;
  Result := ASOContinue;
end;

{ FCN_SquareWave }

procedure FCN_SquareWave.SimpleFunction;
var
  X: TASR;
begin
  Args.Extract(X).Close;
  Result := ASO(SquareWave(X));
end;

{ FCN_TriangleWave }

procedure FCN_TriangleWave.SimpleFunction;
var
  X: TASR;
begin
  Args.Extract(X).Close;
  Result := ASO(TriangleWave(X));
end;

{ FCN_SawtoothWave }

procedure FCN_SawtoothWave.SimpleFunction;
var
  X: TASR;
begin
  Args.Extract(X).Close;
  Result := ASO(SawtoothWave(X));
end;

{ FCN_BlendModes }

procedure FCN_BlendModes.SimpleFunction;
begin
  Args.Close;
  Result := TAlgosimArray.CreateWithValue(BlendModeNames);
end;

{ TNamedObjFcn }

procedure TNamedObjFcn.DoExecute;

  function Briefly(const AText: string): string;
  begin
    if AText.Length > 110 then
      Result := Copy(AText, 1, 100) + '...'
    else
      Result := AText;
  end;

var
  Arg: TAlgosimObject;
  Name: string;
begin
  CheckNumArgs([1, 2]);
  if not ExtractRef(0, Arg) then Exit;
  if not EvalChildren(1) then Exit;
  if ChildCount = 2 then
    Args.Skip.Extract(Name)
  else if IsSymbol(Children[0]) then
    Name := TASSymbolExprNode(Children[0]).Symbol
  else
    Name := Briefly(Arg.ToPreviewString);
  HandleNamedObject(Arg, Name);
end;

{ FCN_Display }

procedure FCN_Display.HandleNamedObject(AObject: TAlgosimObject;
  const AName: string);
begin
  Context.Perform(CLIENT_COMMAND_DISPLAY, NativeInt(AObject), NativeInt(PChar(AName)))
end;

{ FCN_Window }

procedure FCN_Window.HandleNamedObject(AObject: TAlgosimObject;
  const AName: string);
begin
  Context.Perform(CLIENT_COMMAND_WINDOW, NativeInt(AObject), NativeInt(PChar(AName)))
end;

{ FCN_ComputePixmap }

procedure FCN_ComputePixmap.DoExecute;
const
  ARG_WIDTH = 0;
  ARG_HEIGHT = 1;
  ARG_INDEX_SYMBOLX = 2;
  ARG_INDEX_SYMBOLY = 3;
  ARG_INDEX_EXPRESSION = 4;
var
  symbolx, symboly: string;
  symbolsx, symbolsy: TList<TASExprNode>;
  W, H: Integer;
begin

  CheckNumArgs(5);
  if not EvalChild(ARG_WIDTH) then Exit;
  if not EvalChild(ARG_HEIGHT) then Exit;
  CheckSymbol(ARG_INDEX_SYMBOLX);
  CheckSymbol(ARG_INDEX_SYMBOLY);
  symbolx := TASSymbolExprNode(Children[ARG_INDEX_SYMBOLX]).Symbol;
  symboly := TASSymbolExprNode(Children[ARG_INDEX_SYMBOLY]).Symbol;

  Args
    .ExtractPos(W)
    .ExtractPos(H);

  symbolsx := TList<TASExprNode>.Create;
  try

    FindSymbols(Children[ARG_INDEX_EXPRESSION], symbolx, symbolsx);

    symbolsy := TList<TASExprNode>.Create;
    try

      FindSymbols(Children[ARG_INDEX_EXPRESSION], symboly, symbolsy);

      Result := ASO(
        TASPixmap.Generate(W, H,
          function(X, Y: Integer): TASPixel
          var
            res: TAlgosimObject;
          begin
            PopulateSymbols(symbolsx, ASOInt(x));
            PopulateSymbols(symbolsy, ASOInt(y));
            Children[ARG_INDEX_EXPRESSION].Evaluate;
            res := Children[ARG_INDEX_EXPRESSION].Value;
            CheckFailure(res);
            Result := res.ToPixel;
          end
        )
      );

    finally
      symbolsy.Free;
    end;

  finally
    symbolsx.Free;
  end;

end;

{ FCN_ColorDialog }

procedure FCN_ColorDialog.SimpleFunction;
var
  Color: TRGB;
  ColorInt: TColor;
  OK: Boolean;
begin
  Args.Extract(Color, clRed).Close;
  ColorInt := Color;
  if Context.Perform(CLIENT_COMMAND_COLORDIALOG, NativeInt(@ColorInt), NativeInt(@OK)) then
    if OK then
      Result := ASOColor(ColorInt)
    else
      Result := ASO(failure, SUserCanceled)
  else
    Result := ASO(failure);
end;

{ FCN_FontDialog }

procedure FCN_FontDialog.SimpleFunction;
var
  Struct: TAlgosimStructure;
  Font: TFont;
  OK: Boolean;
begin

  CheckNumArgs([0, 1]);
  if Args.Count = 1 then
    Args.Extract(Struct).Close
  else
    Struct := nil;

  Font := TFont.Create;
  try

    if Assigned(Struct) and Struct.HasMember('name') then
      Font.Name := Struct['name'].ToString;

    if Assigned(Struct) and Struct.HasMember('size') then
      Font.Size := Struct['size'].ToInt32;

    if Assigned(Struct) and Struct.HasMember('color') then
      Font.Color := Struct['color'].ToColor;

    Font.Style := [];

    if Assigned(Struct) and Struct.HasMember('bold') and Struct['bold'].ToBoolean then
      Font.Style := Font.Style + [fsBold];

    if Assigned(Struct) and Struct.HasMember('italic') and Struct['italic'].ToBoolean then
      Font.Style := Font.Style + [fsItalic];

    if Assigned(Struct) and Struct.HasMember('underline') and Struct['underline'].ToBoolean then
      Font.Style := Font.Style + [fsUnderline];

    if Assigned(Struct) and Struct.HasMember('strikethrough') and Struct['strikethrough'].ToBoolean then
      Font.Style := Font.Style + [fsStrikeOut];

    if Context.Perform(CLIENT_COMMAND_FONTDIALOG, NativeInt(Font), NativeInt(@OK)) then
      if OK then
        Result := TAlgosimStructure.CreateWithValue(
          [
            sm('name', ASO(Font.Name)),
            sm('size', ASOInt(Font.Size)),
            sm('color', ASOColor(ColorToRGB(Font.Color))),
            sm('bold', ASO(fsBold in Font.Style)),
            sm('italic', ASO(fsItalic in Font.Style)),
            sm('underline', ASO(fsUnderline in Font.Style)),
            sm('strikethrough', ASO(fsStrikeOut in Font.Style))
          ]
        )
      else
        Result := ASO(failure, SUserCanceled)
    else
      Result := ASO(failure);

  finally
    Font.Free;
  end;

end;

{ FCN_FileExists }

procedure FCN_FileExists.SimpleFunction;
var
  FileName: string;
begin
  Args.Extract(FileName).Close;
  Result := ASO(FileExists(FileName));
end;

{ FCN_FileSize }

procedure FCN_FileSize.SimpleFunction;
var
  FileName: string;
  h: HFILE;
  s: Int64;
begin
  Args.Extract(FileName).Close;
  if not FileExists(FileName) then
    raise EFileNotFoundException.Create('File not found.');
  h := CreateFile(PChar(FileName), GENERIC_READ, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  if h = INVALID_HANDLE_VALUE then
    RaiseLastOSError;
  try
    s := 0;
    if not GetFileSizeEx(h, s) then
      RaiseLastOSError;
  finally
    CloseHandle(h);
  end;
  Result := ASOInt(s);
end;

{ FCN_FileName }

procedure FCN_FileName.SimpleFunction;
var
  S: string;
begin
  Args.Extract(S).Close;
  Result := ASO(ExtractFileName(S));
end;

{ FCN_PrettyFileName }

procedure FCN_PrettyFileName.SimpleFunction;
var
  S: string;
begin
  Args.Extract(S).Close;
  Result := ASO(TPath.GetFileNameWithoutExtension(S));
end;

{ FCN_FilePath }

procedure FCN_FilePath.SimpleFunction;
var
  S: string;
begin
  Args.Extract(S).Close;
  Result := ASO(ExtractFilePath(S));
end;

{ FCN_FileExt }

procedure FCN_FileExt.SimpleFunction;
var
  S: string;
begin
  Args.Extract(S).Close;
  Result := ASO(ExtractFileExt(S));
end;

{ FCN_DeleteFile }

procedure FCN_DeleteFile.SimpleFunction;
var
  S: string;
begin
  Args.Extract(S).Close;
  if DeleteFile(PChar(S)) then
    Result := ASO(success)
  else
    RaiseLastOSError;
end;

{ FCN_CreateDirectory }

procedure FCN_CreateDirectory.SimpleFunction;
var
  S: string;
begin
  Args.Extract(S).Close;
  if ForceDirectories(S) and DirectoryExists(S) then
    Result := ASO(success)
  else
    Result := ASO(failure);
end;

{ FCN_DeleteDirectory }

procedure FCN_DeleteDirectory.SimpleFunction;
var
  S: string;
begin
  Args.Extract(S).Close;
  TDirectory.Delete(S);
  if not DirectoryExists(S) then
    Result := ASO(success)
  else
    Result := ASO(failure);
end;

{ FCN_DirectoryExists }

procedure FCN_DirectoryExists.SimpleFunction;
var
  S: string;
begin
  Args.Extract(S).Close;
  Result := ASO(DirectoryExists(S));
end;

{ FCN_FileList }

procedure FCN_FileList.SimpleFunction;
var
  S, P: string;
begin
  Args.Extract(S).Extract(P, '*').Close;
  Result := TAlgosimArray.CreateWithValue(TDirectory.GetFiles(S, P));
end;

{ FCN_DirectoryList }

procedure FCN_DirectoryList.SimpleFunction;
var
  S: string;
begin
  Args.Extract(S).Close;
  Result := TAlgosimArray.CreateWithValue(TDirectory.GetDirectories(S));
end;

{ FCN_FileOpenDialog }

procedure FCN_FileOpenDialog.SimpleFunction;
var
  FDI: TFileDialogInfo;
begin

  FDI := TFileDialogInfo.Create;
  try

    FDI.DialogKind := fdkOpen;

    Args
      .Extract(FDI.FileName)
      .Extract(FDI.Filters)
      .Extract(FDI.MultiSel, False)
      .Close;

    if Context.Perform(CLIENT_COMMAND_FILEDIALOG, NativeInt(FDI)) then
      if not FDI.Canceled then
        if FDI.MultiSel then
          Result := TAlgosimArray.CreateWithValue(FDI.Files)
        else
          Result := ASO(FDI.FileName)
      else
        Result := ASO(failure, SUserCanceled)
    else
      Result := ASO(failure);

  finally
    FDI.Free;
  end;

end;

{ FCN_FileSaveDialog }

procedure FCN_FileSaveDialog.SimpleFunction;
var
  FDI: TFileDialogInfo;
begin

  FDI := TFileDialogInfo.Create;
  try

    FDI.DialogKind := fdkSave;

    Args
      .Extract(FDI.FileName)
      .Extract(FDI.Filters)
      .Extract(FDI.DefaultExt, '')
      .Close;

    if Context.Perform(CLIENT_COMMAND_FILEDIALOG, NativeInt(FDI)) then
      if not FDI.Canceled then
        Result := ASO(FDI.FileName)
      else
        Result := ASO(failure, SUserCanceled)
    else
      Result := ASO(failure);

  finally
    FDI.Free;
  end;

end;

{ FCN_IsCarolNumber }

procedure FCN_IsCarolNumber.SimpleFunction;
var
  N: TASI;
begin
  Args.Extract(N).Close;
  Result := ASO(ASNum.IsCarolNumber(N));
end;

{ FCN_StructKeys }

procedure FCN_StructKeys.SimpleFunction;
var
  S: TAlgosimStructure;
  i: Integer;
begin
  Args.Extract(S).Close;
  Result := TAlgosimArray.Create;
  for i := 1 to S.MemberCount do
    Result.AddElement(ASO(S.Members[i].Name));
end;

{ FCN_Digits }

procedure FCN_Digits.SimpleFunction;
var
  x: TAlgosimNumber;
  N: TASI;
  R: TRationalNumber;
  lim: Integer;
  mode: string;
  I, F: TArray<Integer>;
begin
  Args.Extract(x).ExtractNonNeg(lim, 64).Extract(mode, ['fractional', 'significant'], 'fractional').Close;
  if x.TryToASI(N) then
  begin
    I := ASNum.GetDigits(N);
    TReverser<Integer>.Reverse(I);
    Result := TAlgosimArray.CreateWithValue(I)
  end
  else if x.TryToRat(R) then
  begin
    if mode = 'significant' then
      I := ASNum.GetDigits(R, lim, rdmSignificant, False, False, F)
    else
      I := ASNum.GetDigits(R, lim, rdmFractional, False, False, F);
    TReverser<Integer>.Reverse(I);
    Result := ASO(
      [
        sm('int', TAlgosimArray.CreateWithValue(I)),
        sm('frac', TAlgosimArray.CreateWithValue(F))
      ]
    );
  end
  else
    ErrInvalidArguments;
end;

{ FCN_FractionParts }

procedure FCN_FractionParts.SimpleFunction;
var
  x: TAlgosimNumber;
begin
  Args.Extract(x).Close;
  Result := ASORationalNumber(x.ToRat);
end;

{ FCN_ExampleData }

procedure FCN_ExampleData.SimpleFunction;
var
  ObjName, SubObjName: string;
begin
  Args.Extract(ObjName).Extract(SubObjName, '').Close;
  if SameText(SubObjName, 'license') then
    Result := ASO(LoadResLicense(ObjName))
  else
    Result := LoadResObject(ObjName);
end;

{ FCN_LeftAlign }

procedure FCN_LeftAlign.SimpleFunction;
var
  Table: TAlgosimTable;
begin
  Args.MoveObject<TAlgosimTable>(Value, Table).Close;
  Table.Alignment := taLeftJustify;
end;

{ FCN_RightAlign }

procedure FCN_RightAlign.SimpleFunction;
var
  Table: TAlgosimTable;
begin
  Args.MoveObject<TAlgosimTable>(Value, Table).Close;
  Table.Alignment := taRightJustify;
end;

{ FCN_CenterText }

procedure FCN_CenterText.SimpleFunction;
var
  Table: TAlgosimTable;
begin
  Args.MoveObject<TAlgosimTable>(Value, Table).Close;
  Table.Alignment := taCenter;
end;

{ FCN_MatrixPlot }

procedure FCN_MatrixPlot.SimpleFunction;
var
  M: TRealMatrix;
  Modulus: Boolean;
  C: TRGB;
  L: TAlgosimArray;
  W, H: Integer;
  fo: TAlgosimFunctionObject;
  f: TNumColorFunc<TASR>;
const
  Modes: array[Boolean] of TMatrixNormalizationKind = (mnkMinMax, mnkModulus);
begin
  if Args.PeekAt(1) is TAlgosimFunctionObject then
  begin
    Args
      .Extract(M)
      .Extract(fo)
      .Extract(Modulus, False)
      .ExtractPos(W, 200)
      .ExtractPos(H, 0)
      .Close;
    if H = 0 then
      H := Ceil(W * M.Size.Rows / M.Size.Cols);
    f := function(const Value: TASR): TASPixel
      begin
        with fo.Execute(Context, [ASO(Value)], True) do
          try
            Result := ToPixel;
          finally
            Free;
          end;
      end;
    Result := ASO(MatrixPlot(M, f, W, H, Modes[Modulus]))
  end
  else if Args.PeekAt(1) is TAlgosimArray then
  begin
    Args
      .Extract(M)
      .Extract(L)
      .Extract(Modulus, False)
      .ExtractPos(W, 200)
      .ExtractPos(H, 0)
      .Close;
    if H = 0 then
      H := Ceil(W * M.Size.Rows / M.Size.Cols);
    if L.ElementCount >= 3 then
      Result := ASO(MatrixPlot(M, L[1].ToColor, L[2].ToColor, L[3].ToColor, W, H, Modes[Modulus]))
    else
      Result := ASO(MatrixPlot(M, L[1].ToColor, L[2].ToColor, W, H, Modes[Modulus]))
  end
  else
  begin
    Args
      .Extract(M)
      .Extract(C, clRed)
      .Extract(Modulus, False)
      .ExtractPos(W, 200)
      .ExtractPos(H, 0)
      .Close;
    if H = 0 then
      H := Ceil(W * M.Size.Rows / M.Size.Cols);
    Result := ASO(MatrixPlot(M, C, W, H, Modes[Modulus]))
  end;
end;

procedure ClientVisErr;
begin
  raise EClientVisualizationError.Create('The front-end couldn''t handle the visualization request.');
end;

{ FCN_Diagram }

procedure FCN_Diagram.SimpleFunction;
var
  Name: string;
  Ref: TAlgosimReference;
begin
  Args.Extract(Name, '').Close;
  Ref := nil;
  if
    Context.Perform(CLIENT_COMMAND_SETDIAGRAM, NativeInt(PChar(Name)), NativeInt(@Ref))
  then
    Result := Ref
  else
    ClientVisErr;
end;

{ FCN_Scene }

procedure FCN_Scene.SimpleFunction;
var
  Name: string;
  Ref: TAlgosimReference;
begin
  Args.Extract(Name, '').Close;
  Ref := nil;
  if
    Context.Perform(CLIENT_COMMAND_SETSCENE, NativeInt(PChar(Name)), NativeInt(@Ref))
  then
    Result := Ref
  else
    ClientVisErr;
end;

{ TASVisualizationFunction }

destructor TASVisualizationFunction.Destroy;
begin
  FreeAndNil(FVisual);
  inherited;
end;

procedure TASVisualizationFunction.SimpleFunction;
var
  Ref: TAlgosimReference;
begin
  if Assigned(FVisual) then
    try
      Ref := nil;
      if
        Context.Perform(CLIENT_COMMAND_ADDVISUAL, NativeInt(FVisual as TVisual), NativeInt(@Ref))
          and
        Assigned(Ref)
      then
        Result := Ref
      else
        ClientVisErr;
    finally
      FreeAndNil(FVisual);
    end;
end;

{ FCN_BarChart }

procedure FCN_BarChart.SimpleFunction;
var
  L: TArray<TAlgosimObject>;
  CDL: TCategoryDataList;
  N: Integer;
  D: Double;
  R: TDataRange;
begin
  L := Args.ExtractArray;
  CDL := GetCategoryData(L, @N, @R);
  D := 0.5 + 1.25 * N;
  FVisual := TVisual.Create2D(vkBarChart, CDL,
    procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
    begin
      ACtl.View.&Set(-0.1*D, 1.1*D, Min(-0.1*R.Max, 1.1*R.Min), 1.1*R.Max);
      ACtl.Axes.X.NumbersVisible := False;
      ACtl.Axes.X.TicksVisible := False;
      var BC := (ADrawable as TBarChart);
      for var LBar in BC.Bars do
        LBar.Style.BorderWidth := 0;
    end
  );
  inherited;
end;

{ FCN_PieChart }

procedure FCN_PieChart.SimpleFunction;
var
  L: TArray<TAlgosimObject>;
  CDL: TCategoryDataList;
begin
  L := Args.ExtractArray;
  CDL := GetCategoryData(L);
  FVisual := TVisual.Create2D(vkPieChart, CDL,
    procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
    begin
      ACtl.View.&Set(-1.5, 1.5, -1.5, 1.5);
      ACtl.Axes.X.Visible := False;
      ACtl.Axes.Y.Visible := False;
      ACtl.AutoNormalize := True;
    end
  );
  inherited;
end;

{ FCN_Histogram }

procedure FCN_Histogram.SimpleFunction;
var
  L: TArray<TASR>;
  HD: THistogramData;
  R: TDataRange;
begin
  L := Args.ExtractRealNumbers;
  HD := GetHistogramData(L, @R);
  FVisual := TVisual.Create2D(vkHistogram, HD,
    procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
    var
      Histogram: THistogram;
      MaxVal: Int64;
      A, B, A′: Double;
    begin
      Histogram := ADrawable as THistogram;
      Histogram.Style.BorderWidth := 0;
      if (R.Span > 0) and (Histogram.BinWidth >= R.Span / 5) then
        Histogram.BinWidth := IntPower(10, Floor(Log10(R.Span / 5)));
      MaxVal := Histogram.MaxBinValue;
      R.Max := R.Max + Histogram.BinWidth;
      A := R.Min - 0.1 * R.Span;
      B := R.Max + 0.1 * R.Span;
      if (R.Max <= 0) or (A > -B/9) then
      begin
        A′ := -B/9;
        if (R.Max > 0) and ((B - A) / (B - A′) >= 0.75) then
          A := A′
        else
        begin
          A := R.Min - 0.2 * R.Span;
          ACtl.Axes.Y.Position := R.Min - 0.1 * R.Span;
        end;
      end;
      ACtl.View.&Set(A, B, -0.1 * MaxVal, 1.1 * MaxVal);
    end
  );
  inherited;
end;

{ FCN_ScatterPlot }

procedure FCN_ScatterPlot.SimpleFunction;
var
  List: TArray<Double>;
  RX, RY, RZ: TDataRange;
begin
  var n := 0;
  Args.ExtractPointListRn(List, n);
  case n of
    2:
      begin
        var SD := GetScatterDataR2(DoubleListToASR2s(List), @RX, @RY);
        FVisual := TVisual.Create2D(vkXYPlot, SD,
          procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
          var
            A, B: Double;
          begin
            A := RY.Min - 0.1*RY.Span;
            B := RY.Max + 0.1*RY.Span;
            ACtl.View.&Set(RX.Min - 0.1*RX.Span, RX.Max + 0.1*RX.Span, A, B, True);
          end
        );
      end;
    3:
      begin
        var SD := GetScatterDataR3(DoubleListToASR3s(List), @RX, @RY, @RZ);
        FVisual := TVisual.Create3D(vkXYZPlot, SD);
      end;
    5:
      begin
        var SD := GetScatterDataR3cs(List, @RX, @RY, @RZ);
        FVisual := TVisual.Create3D(vkXYZcsPlot, SD);
      end
  else
    raise EInvArgs.Create('Data to plot must be of the form (x, y), (x, y, z), or (x, y, z, color, radius).');
  end;

  inherited;
end;

{ FCN_LineChart }

procedure FCN_LineChart.SimpleFunction;
var
  L: TArray<TASR2>;
  SD: TScatterDataR2;
  RX, RY: TDataRange;
begin
  L := Args.ExtractPointsR2;
  SD := GetScatterDataR2(L, @RX, @RY);
  FVisual := TVisual.Create2D(vkXYPlot, SD,
    procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
    var
      A, B: Double;
    begin
      A := RY.Min - 0.1*RY.Span;
      B := RY.Max + 0.1*RY.Span;
      ACtl.View.&Set(RX.Min - 0.1*RX.Span, RX.Max + 0.1*RX.Span, A, B, True);
    end,
    procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
    begin
      with ADrawable as TXYPlot do
      begin
        Points := False;
        PointSize := 6;
        Lines := True;
      end;
    end
  );
  inherited;
end;

{ FCN_AreaChart }

procedure FCN_AreaChart.SimpleFunction;
var
  L: TArray<TASR2>;
  SD: TScatterDataR2;
  RX, RY: TDataRange;
begin
  L := Args.ExtractPointsR2;
  SD := GetScatterDataR2(L, @RX, @RY);
  FVisual := TVisual.Create2D(vkXYPlot, SD,
    procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
    var
      A, B: Double;
    begin
      A := RY.Min - 0.1*RY.Span;
      B := RY.Max + 0.1*RY.Span;
      ACtl.View.&Set(RX.Min - 0.1*RX.Span, RX.Max + 0.1*RX.Span, A, B, True);
    end,
    procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
    begin
      with ADrawable as TXYPlot do
      begin
        Points := False;
        PointSize := 6;
        Area := True;
      end;
    end
  );
  inherited;
end;

{ FCN_Graph }

procedure FCN_Graph.SimpleFunction;

  function ASOs(AVector: TRealVector): TArray<TAlgosimObject>;
  begin
    SetLength(Result, AVector.Dimension);
    for var i := 0 to High(Result) do
      Result[i] := ASO(AVector[i]);
  end;

var
  VarSpecs: TArray<TRealVector>;
  Index: TRealVector;

  function NextIndex: Boolean;
  begin
    for var i := Index.Dimension - 1 downto 0 do
      if Index[i] + VarSpecs[i][2] <= VarSpecs[i][1] then
      begin
        if VarSpecs[i][2] <= 0 then
          ErrInvalidArguments;
        Index[i] := Index[i] + VarSpecs[i][2];
        Exit(True);
      end
      else
        Index[i] := VarSpecs[i][0];
    Result := False;
  end;

var
  Fcn: TAlgosimFunctionObject;
  Args: TArgumentExtractor;
  VarSpec: TRealVector;
  amin, amax, adelta: TASR;
  Value: TRealVector;
  Values: TList<TRealVector>;
  i: Integer;
  Image: TASR;

const
  N = DefPlotN;

begin

  Args := Self.Args.Extract(Fcn);
  if Self.Args.PeekAt(1) is TAlgosimVector then
  begin
    var LAdjN := N;
    if Self.Args.Count > 2 then
      LAdjN := 100;
    while Args.ArgExists do
    begin
      Args := Args.Extract(VarSpec);
      if VarSpec.Dimension = 2 then
        VarSpec := ASR3(VarSpec[0], VarSpec[1], (VarSpec[1] - VarSpec[0]) / LAdjN)
      else if VarSpec.Dimension <> 3 then
        ErrInvalidArguments;
      TArrBuilder<TRealVector>.Add(VarSpecs, VarSpec); {noexcept}
    end;
  end
  else
  begin
    Args.Extract(amin).Extract(amax).ExtractPos(adelta, 0).Close;
    if adelta = 0 then
      adelta := (amax - amin) / N; // compiler bug RSP-29733
    VarSpec := ASR3(amin, amax, adelta);
    VarSpecs := [VarSpec];
  end;
  Values := TList<TRealVector>.Create;
  try
    Index := TRealVector.Create(Length(VarSpecs));
    for i := 0 to High(VarSpecs) do
      Index[i] := VarSpecs[i][0];
    repeat
      Value := TRealVector.Create(Index.Dimension + 1);
      for i := 0 to Index.Dimension - 1 do
        Value[i] := Index[i];
      with Fcn.Execute(Context, ASOs(Index), True) do
        try
          if not TryToASR(Image) then
            Continue;
        finally
          Free;
        end;
      Value[Value.Dimension - 1] := Image;
      Values.Add(Value);
    until not NextIndex;
    Result := ASO(TRealMatrix.CreateFromRows(Values.ToArray));
  finally
    Values.Free;
  end;
end;

{ FCN_Plot }

procedure FCN_Plot.DoExecute;

  function IsRelational(ANode: TASExprNode): Boolean;
  begin
    Result := (ANode is FCN_Equals) or
              (ANode is FCN_LessThan) or
              (ANode is FCN_LessThanOrEqualTo) or
              (ANode is FCN_GreaterThan) or
              (ANode is FCN_GreaterThanOrEqualTo);
  end;

const
  N = DefPlotN;

begin

  if (ChildCount > 0) and IsRelational(Children[0]) then
  begin

    if Children[0] is FCN_Equals then
    begin

      const Equation = Children[0];

      if Equation.ChildCount <> 2 then
        raise EInvArgs.Create('Can only plot a region defined by a single equation.');

      const LHS = Equation.Children[0];
      const RHS = Equation.Children[1];

      var Implicit := False;

      var Axis := Default(TCartesianAxis);
      var LFcnExpr := TASExprNode(nil);
      var Variable := '';

      if IsSymbol(LHS, 'y') then
      begin
        Axis := TCartesianAxis.X;
        LFcnExpr := RHS;
        Variable := 'x';
      end
      else if IsSymbol(LHS, 'x') then
      begin
        Axis := TCartesianAxis.Y;
        LFcnExpr := RHS;
        Variable := 'y';
      end
      else if IsSymbol(RHS, 'y') then
      begin
        Axis := TCartesianAxis.X;
        LFcnExpr := LHS;
        Variable := 'x';
      end
      else if IsSymbol(RHS, 'x') then
      begin
        Axis := TCartesianAxis.Y;
        LFcnExpr := LHS;
        Variable := 'y';
      end
      else
        Implicit := True;

      if not Implicit then
      begin

        if not EvalChildren(1) then Exit;

        var amin, amax, adelta: TASR;
        Args.Skip.Extract(amin, -10).Extract(amax, 10).ExtractPos(adelta, 0).Close;
        if adelta = 0 then
          adelta := (amax - amin) / N; // compiler bug RSP-29733

        var L := TList<TASR2>.Create;
        try

          var symbols := TList<TASExprNode>.Create;
          try
            FindSymbols(LFcnExpr, Variable, symbols);
            var a := amin;
            var b: TASR;
            while a <= amax do
            begin
              PopulateSymbols(symbols, ASO(a));
              LFcnExpr.Evaluate;
              var res := LFcnExpr.Value;
              CheckFailure(res);
              if res.TryToASR(b) then
                case Axis of
                  TCartesianAxis.X:
                    L.Add(TASR2.Create(a, b));
                  TCartesianAxis.Y:
                    L.Add(TASR2.Create(b, a));
                end;
              a := a + adelta;
            end;
          finally
            symbols.Free;
          end;

          var RX, RY, RZ: TDataRange;
          var ScatterData := GetScatterDataR2(L.ToArray, @RX, @RY);
          var Visual := TVisual.Create2D(vkXYPlot, ScatterData,
            procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
            var
              A, B: Double;
            begin
              A := RY.Min - 0.1*RY.Span;
              B := RY.Max + 0.1*RY.Span;
              ACtl.View.&Set(RX.Min - 0.1*RX.Span, RX.Max + 0.1*RX.Span, A, B, True);
            end
          );
          try
            var Ref: TAlgosimReference := nil;
            if
              Context.Perform(CLIENT_COMMAND_ADDVISUAL, NativeInt(Visual), NativeInt(@Ref))
                and
              Assigned(Ref)
            then
              Result := Ref
            else
              ClientVisErr;
          finally
            Visual.Free;
          end;

        finally
          L.Free;
        end;

      end
      else { Implicit graph: plot(implicit equation[, ...]), e.g. plot(x^2 + y^2 = 1) }
      begin

        var LSampleMeta := Default(TSampleMeta);

        if not EvalChildren(1) then Exit;

        var xrange, yrange: TRealVector;
        var opts: TSysCharSet;

        Args
          .Skip
          .Extract(xrange, ASR2(-10, 10))
          .Extract(yrange, ASR2(-10, 10))
          .Extract(opts, restr, ['i', 's'], defval, ['i', 's'])
          .Close;

        if xrange.Dimension in [2, 3] then
        begin
          LSampleMeta.xmin := xrange[0];
          LSampleMeta.xmax := xrange[1];
          if LSampleMeta.xspan <= 0 then
            ErrInvalidArguments;
          if xrange.Dimension = 3 then
            if xrange[2] > 0 then
              LSampleMeta.nx := Round(LSampleMeta.xspan / xrange[2]) + 1
            else
              ErrInvalidArguments;
        end
        else
          ErrInvalidArguments;

        if yrange.Dimension in [2, 3] then
        begin
          LSampleMeta.ymin := yrange[0];
          LSampleMeta.ymax := yrange[1];
          if LSampleMeta.yspan <= 0 then
            ErrInvalidArguments;
          if yrange.Dimension = 3 then
            if yrange[2] > 0 then
              LSampleMeta.ny := Round(LSampleMeta.yspan / yrange[2]) + 1
            else
              ErrInvalidArguments;
        end
        else
          ErrInvalidArguments;

        const SampleCount = Sqr(TNumericSettingsCache.Numerics_ContourSamplesPerAxis);
        // ⎰ nx * ny = SampleCount
        // ⎱ nx / ny = Aspect
        //    ⇓
        // the default LSampleMeta.n* values below

        if LSampleMeta.nx = 0 then
          LSampleMeta.nx := Ceil(Sqrt(SampleCount / LSampleMeta.Aspect));
        if LSampleMeta.ny = 0 then
          LSampleMeta.ny := Ceil(Sqrt(SampleCount * LSampleMeta.Aspect));

        const LAutoBounds = Args.Count = 1;

        var LSamples := TSamples(nil);

        var L := TList<TASR>.Create;
        try

          var LDifference := Equation.MutatedExpressionRootedHere(FCN_Subtract);
          try

            var ysyms := TList<TASExprNode>.Create;
            try

              FindSymbols(LDifference.Root, 'y', ysyms);
              var xsyms := TList<TASExprNode>.Create;
              try

                const tc1 = GetTickCount64;

                FindSymbols(LDifference.Root, 'x', xsyms);
                var ydelta := LSampleMeta.ydelta;
                var xdelta := LSampleMeta.xdelta;
                for var iy := 0 to LSampleMeta.ny - 1 do
                begin
                  var y := LSampleMeta.ymax - iy * ydelta;
                  PopulateSymbols(ysyms, ASO(y));
                  for var ix := 0 to LSampleMeta.nx - 1 do
                  begin
                    var x := LSampleMeta.xmin + ix * xdelta;
                    PopulateSymbols(xsyms, ASO(x));
                    LDifference.Evaluate;
                    var res := LDifference.Root.Value;
                    CheckFailure(res);
                    var z: TASR;
                    if res.TryToASR(z) then
                      L.Add(z)
                    else
                      L.Add(NaN);
                  end;
                end;

                const tc2 = GetTickCount64;
                const ComputationTimeMS = UInt64(tc2 - tc1);

                var LContourOptions := ZeroContour;
                LContourOptions.Interpolate := AnsiChar('i') in opts;
                LContourOptions.Simplify    := AnsiChar('s') in opts;

                var LContour := ASContours.Contours(LSampleMeta, L.ToArray, LContourOptions);

                const LBoundingBox = ContourBoundingBox(LContour);
//                OutputDebugString(PChar(LBoundingBox.ToString));
                if
                  LAutoBounds
                    and
                  LBoundingBox.StrictlyInsideY(LSampleMeta.Rect)
                    and
                  (LBoundingBox.AreaY < 0.5 * LSampleMeta.Rect.AreaY)
                    and
                  (LBoundingBox.AreaY > 0.000001 * LSampleMeta.Rect.AreaY)
                    and
                  (ComputationTimeMS < 2_000)
                then
                begin
                  // Worth redoing with less wasteful bounds
                  L.Clear;
                  LSampleMeta.xmin := LBoundingBox.Left - LBoundingBox.Width / 10 - 0.01;
                  LSampleMeta.xmax := LBoundingBox.Right + LBoundingBox.Width / 10 + 0.01;
                  LSampleMeta.ymin := LBoundingBox.Bottom - LBoundingBox.HeightY / 10 - 0.01;
                  LSampleMeta.ymax := LBoundingBox.Top + LBoundingBox.HeightY / 10 + 0.01;
                  LSampleMeta.nx := Ceil(Sqrt(SampleCount / LSampleMeta.Aspect));
                  LSampleMeta.ny := Ceil(Sqrt(SampleCount * LSampleMeta.Aspect));
                  ydelta := LSampleMeta.ydelta;
                  xdelta := LSampleMeta.xdelta;
                  for var iy := 0 to LSampleMeta.ny - 1 do
                  begin
                    var y := LSampleMeta.ymax - iy * ydelta;
                    PopulateSymbols(ysyms, ASO(y));
                    for var ix := 0 to LSampleMeta.nx - 1 do
                    begin
                      var x := LSampleMeta.xmin + ix * xdelta;
                      PopulateSymbols(xsyms, ASO(x));
                      LDifference.Evaluate;
                      var res := LDifference.Root.Value;
                      CheckFailure(res);
                      var z: TASR;
                      if res.TryToASR(z) then
                        L.Add(z)
                      else
                        L.Add(NaN);
                    end;
                  end;
                  LContour := ASContours.Contours(LSampleMeta, L.ToArray, LContourOptions);
                end;

                var RX, RY: TDataRange;
                var ScatterData := GetScatterDataR2(LContour, @RX, @RY);
                var Visual := TVisual.Create2D(vkXYPlot, ScatterData,
                  procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
                  var
                    A, B: Double;
                  begin
                    A := RY.Min - 0.1*RY.Span;
                    B := RY.Max + 0.1*RY.Span;
                    ACtl.View.&Set(RX.Min - 0.1*RX.Span, RX.Max + 0.1*RX.Span, A, B, True);
                  end,
                  procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
                  begin
                    with ADrawable as TXYPlot do
                    begin
                      Points := False;
                      Lines := True;
                    end;
                  end
                );
                try
                  if LContourOptions.Simplify then
                  begin
                    var LCircles := TDictionary<Integer, TCircleRec>.Create;
                    try
                      ASContours.CircleDetect(LSampleMeta, LContour, LCircles);
                    except
                      LCircles.Free;
                      raise;
                    end;
                    ScatterData.Metadata := LCircles;
                  end;
                  var Ref: TAlgosimReference := nil;
                  if
                    Context.Perform(CLIENT_COMMAND_ADDVISUAL, NativeInt(Visual), NativeInt(@Ref))
                      and
                    Assigned(Ref)
                  then
                    Result := Ref
                  else
                    ClientVisErr;
                finally
                  Visual.Free;
                end;

              finally
                xsyms.Free;
              end;

            finally
              ysyms.Free;
            end;

          finally
            LDifference.Free;
          end;

        finally
          L.Free;
        end;

      end;

    end

    else
    begin

      const Inequality = Children[0];

      if not (Inequality.ChildCount in [2, 3]) then
        raise EInvArgs.Create('Can only plot a region defined by one or two inequalities.');

      if Inequality.ChildCount = 2 then
      begin

        const LHS = Inequality.Children[0];
        const RHS = Inequality.Children[1];

        var Axis: TCartesianAxis;
        var LFcnExpr: TASExprNode;
        var Variable: string;

        if IsSymbol(LHS, 'y') then
        begin
          Axis := TCartesianAxis.X;
          LFcnExpr := RHS;
          Variable := 'x';
        end
        else if IsSymbol(LHS, 'x') then
        begin
          Axis := TCartesianAxis.Y;
          LFcnExpr := RHS;
          Variable := 'y';
        end
        else if IsSymbol(RHS, 'y') then
        begin
          Axis := TCartesianAxis.X;
          LFcnExpr := LHS;
          Variable := 'x';
        end
        else if IsSymbol(RHS, 'x') then
        begin
          Axis := TCartesianAxis.Y;
          LFcnExpr := LHS;
          Variable := 'y';
        end
        else
          raise EInvArgs.Create('Cannot plot inequality with implicit function.');

        if not EvalChildren(1) then Exit;
        var amin, amax, adelta: TASR;
        Args.Skip.Extract(amin, -10).Extract(amax, 10).ExtractPos(adelta, 0).Close;
        if adelta = 0 then
          adelta := (amax - amin) / N; // compiler bug RSP-29733

        var Ls :=  TList<TSlice>.Create;
        try

          var LUnboundedMin := ((Inequality is FCN_LessThan) or (Inequality is FCN_LessThanOrEqualTo)) xor (LFcnExpr = LHS);
          var LUnboundedMax := ((Inequality is FCN_GreaterThan) or (Inequality is FCN_GreaterThanOrEqualTo)) xor (LFcnExpr = LHS);

          var symbols := TList<TASExprNode>.Create;
          try
            FindSymbols(LFcnExpr, Variable, symbols);
            var a := amin;
            while a <= amax do
            begin
              PopulateSymbols(symbols, ASO(a));
              LFcnExpr.Evaluate;
              var res := LFcnExpr.Value;
              CheckFailure(res);
              var b: TASR;
              if res.TryToASR(b) then
                Ls.Add(TSlice.Create(a, b, b));
              a := a + adelta;
            end;
          finally
            symbols.Free;
          end;

          var RX, RY, RZ: TDataRange;
          var RegionData: TRegionDataR2;
          if Axis = TCartesianAxis.x then
            RegionData := GetRegionDataR2(Ls.ToArray, LUnboundedMin, LUnboundedMax, @RX, @RY)
          else
            RegionData := GetRegionDataR2(Ls.ToArray, LUnboundedMin, LUnboundedMax, @RY, @RX);
          RegionData.Axis := Axis;
          RegionData.UnboundedMin := LUnboundedMin;
          RegionData.UnboundedMax := LUnboundedMax;
          var Visual := TVisual.Create2D(vkRegion, RegionData,
            procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
            var
              A, B: Double;
            begin
              A := RY.Min - 0.1*RY.Span;
              B := RY.Max + 0.1*RY.Span;
              ACtl.View.&Set(RX.Min - 0.1*RX.Span, RX.Max + 0.1*RX.Span, A, B, True);
            end
          );
          try
            var Ref: TAlgosimReference := nil;
            if
              Context.Perform(CLIENT_COMMAND_ADDVISUAL, NativeInt(Visual), NativeInt(@Ref))
                and
              Assigned(Ref)
            then
              Result := Ref
            else
              ClientVisErr;
          finally
            Visual.Free;
          end;

        finally
          Ls.Free;
        end;

      end
      else
      begin

        const LHS = Inequality.Children[0];
        const MT  = Inequality.Children[1];
        const RHS = Inequality.Children[2];

        var Axis := Default(TCartesianAxis);
        var Variable := '';
        if IsSymbol(MT, 'y') then
        begin
          Axis := TCartesianAxis.X;
          Variable := 'x';
        end
        else if IsSymbol(MT, 'x') then
        begin
          Axis := TCartesianAxis.Y;
          Variable := 'y';
        end
        else
          raise EInvArgs.Create('Can only plot a region between two explicit graphs of functions depending on a Cartesian coordinate.');

        var IsLessThan := (Inequality is FCN_LessThan) or (Inequality is FCN_LessThanOrEqualTo);

        if not EvalChildren(1) then Exit;
        var amin, amax, adelta: TASR;
        Args.Skip.Extract(amin, -10).Extract(amax, 10).ExtractPos(adelta, 0).Close;
        if adelta = 0 then
          adelta := (amax - amin) / N; // compiler bug RSP-29733

        var Ls :=  TList<TSlice>.Create;
        try

          var LHSsym := TList<TASExprNode>.Create;
          try
            var RHSsym := TList<TASExprNode>.Create;
            try
              FindSymbols(LHS, Variable, LHSsym);
              FindSymbols(RHS, Variable, RHSsym);
              var a := amin;
              while a <= amax do
              begin
                PopulateSymbols(LHSsym, ASO(a));
                PopulateSymbols(RHSsym, ASO(a));
                LHS.Evaluate;
                var LHSres := LHS.Value;
                CheckFailure(LHSres);
                RHS.Evaluate;
                var RHSres := RHS.Value;
                CheckFailure(RHSres);
                var b, c: TASR;
                if LHSres.TryToASR(b) and RHSres.TryToASR(c) then
                  if IsLessThan then
                    Ls.Add(TSlice.Create(a, b, c))
                  else
                    Ls.Add(TSlice.Create(a, c, b));
                a := a + adelta;
              end;
            finally
              RHSsym.Free;
            end;
          finally
            LHSsym.Free;
          end;

          var RegionData: TRegionDataR2;
          var RX, RY: TDataRange;
          if Axis = TCartesianAxis.x then
            RegionData := GetRegionDataR2(Ls.ToArray, False, False, @RX, @RY)
          else
            RegionData := GetRegionDataR2(Ls.ToArray, False, False, @RY, @RX);
          RegionData.Axis := Axis;
          RegionData.UnboundedMin := False;
          RegionData.UnboundedMax := False;
          var Visual := TVisual.Create2D(vkRegion, RegionData,
            procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
            var
              A, B: Double;
            begin
              A := RY.Min - 0.1*RY.Span;
              B := RY.Max + 0.1*RY.Span;
              ACtl.View.&Set(RX.Min - 0.1*RX.Span, RX.Max + 0.1*RX.Span, A, B, True);
            end
          );
          try
            var Ref: TAlgosimReference := nil;
            if
              Context.Perform(CLIENT_COMMAND_ADDVISUAL, NativeInt(Visual), NativeInt(@Ref))
                and
              Assigned(Ref)
            then
              Result := Ref
            else
              ClientVisErr;
          finally
            Visual.Free;
          end;

        finally
          Ls.Free;
        end;

      end;

    end;

  end
  else
  begin

    if not EvalChildren then Exit;

    var Visual: TVisual;

    var LDim := 0;
    var LList: TArray<Double>;
    Args.ExtractPointListRn(LList, LDim);
    case LDim of
      2:
        begin
          var RX, RY: TDataRange;
          var SD := GetScatterDataR2(DoubleListToASR2s(LList), @RX, @RY);
          Visual := TVisual.Create2D(vkXYPlot, SD,
            procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
            var
              A, B: Double;
            begin
              A := RY.Min - 0.1*RY.Span;
              B := RY.Max + 0.1*RY.Span;
              ACtl.View.&Set(RX.Min - 0.1*RX.Span, RX.Max + 0.1*RX.Span, A, B, True);
            end
          );
        end;
      3:
        begin
          var RX, RY, RZ: TDataRange;
          var SD := GetScatterDataR3(DoubleListToASR3s(LList), @RX, @RY, @RZ);
          Visual := TVisual.Create3D(vkXYZPlot, SD);
        end;
      5:
        begin
          var RX, RY, RZ: TDataRange;
          var SD := GetScatterDataR3cs(LList, @RX, @RY, @RZ);
          Visual := TVisual.Create3D(vkXYZcsPlot, SD);
        end
    else
      raise EInvArgs.Create('Data to plot must be of the form (x, y), (x, y, z), or (x, y, z, color, radius).');
    end;

    try
      var Ref: TAlgosimReference := nil;
      if
        Context.Perform(CLIENT_COMMAND_ADDVISUAL, NativeInt(Visual), NativeInt(@Ref))
          and
        Assigned(Ref)
      then
        Result := Ref
      else
        ClientVisErr;
    finally
      Visual.Free;
    end;

  end;

end;

{ FCN_Heatmap }

procedure FCN_Heatmap.SimpleFunction;
const
  Modes: array[Boolean] of TMatrixNormalizationKind = (mnkMinMax, mnkModulus);
var
  F: TAlgosimFunctionObject;
  vx, vy: TRealVector;
  x0, x1, xd, Dx,
  y0, y1, yd, Dy: TASR;
  xn, yn: TASR;
  C: TAlgosimObject;
  m: Boolean;
  A: TRealMatrix;
  i, j: Integer;
  x, y, z: TASR;
  Obj: TAlgosimObject;
  cf: TNumColorFunc<TASR>;
  pm: TASPixmap;
begin

  const N = Round(5*Sqrt(DefPlotN));
  Args
    .Extract(F)
    .Extract(vx)
    .Extract(vy)
    .Extract(C, nil)
    .Extract(m, False)
    .Close;
  if vx.Dimension in [2, 3] then
  begin
    x0 := vx[0];
    x1 := vx[1];
    Dx := x1 - x0;
    if vx.Dimension = 3 then
      xd := vx[2]
    else
      xd := Dx / N;
  end
  else
    ErrInvalidArguments;
  if vy.Dimension in [2, 3] then
  begin
    y0 := vy[0];
    y1 := vy[1];
    Dy := y1 - y0;
    if vy.Dimension = 3 then
      yd := vy[2]
    else
      yd := Dy / N;
  end
  else
    ErrInvalidArguments;
  if (Dx <= 0) or (Dy <= 0) or IsZero(xd) or IsZero(yd) then
    ErrInvalidArguments;
  xn := Dx / xd;
  yn := Dy / yd;
  if xn < 1 then xn := 1;
  if yn < 1 then yn := 1;
  if (xn > 1E8) or (yn > 1E8) or (xn * yn > 1E8) then
    raise EInvArgs.Create('Too great resolution.');
  A := TRealMatrix.CreateUninitialized(
    TMatrixSize.Create(Round(yn), Round(xn))
  );
  for i := 0 to A.Size.Rows - 1 do
    for j := 0 to A.Size.Cols - 1 do
    begin
      x := x0 + (j + 0.5) * xd;
      y := y1 - (i + 0.5) * yd;
      Obj := F.Execute(Context, [ASO(x), ASO(y)], True);
      try
        z := Obj.ToASR;
      finally
        Obj.Free;
      end;
      A[i, j] := z;
    end;
  if C is TAlgosimFunctionObject then
  begin
    cf := function(const Value: TASR): TASPixel
      begin
        with TAlgosimFunctionObject(C).Execute(Context, [ASO(Value)], True) do
          try
            Result := ToPixel;
          finally
            Free;
          end;
      end;
    pm := MatrixPlot(A, cf, A.Size.Cols, A.Size.Rows, Modes[m])
  end
  else if C is TAlgosimArray then
  begin
    if C.ElementCount >= 3 then
      pm := MatrixPlot(A, C.Elements[1].ToColor, C.Elements[2].ToColor, C.Elements[3].ToColor, A.Size.Cols, A.Size.Rows, Modes[m])
    else
      pm := MatrixPlot(A, C.Elements[1].ToColor, C.Elements[2].ToColor, A.Size.Cols, A.Size.Rows, Modes[m])
  end
  else if Assigned(C) then
    pm := MatrixPlot(A, C.ToColor, A.Size.Cols, A.Size.Rows, Modes[m])
  else
    pm := MatrixPlot(A, clRed, A.Size.Cols, A.Size.Rows, Modes[m]);
  var HMD := THeatmapData.Create;
  HMD.Pixmap := pm;
  HMD.x0 := x0;
  HMD.x1 := x1;
  HMD.y0 := y0;
  HMD.y1 := y1;
  FVisual := TVisual.Create2D(vkHeatmap, HMD,
    procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
    begin
      ACtl.View.&Set(x0 - 0.1*Dx, x1 + 0.1*Dx, y0 - 0.1*Dy, y1 + 0.1*Dy, True);
    end
  );

  inherited;

end;

{ FCN_VectorField }

procedure FCN_VectorField.SimpleFunction;
var
  Dim: Integer;
  F: TAlgosimFunctionObject;
  vx, vy, vz: TRealVector;
  x0, x1, xd, Dx,
  y0, y1, yd, Dy,
  z0, z1, zd, Dz: TASR;
  xn, yn, zn: Integer;
  w: TRealVector;
  x, y, z: TASR;
  i, j, k: Integer;
  Obj: TAlgosimObject;
  VF2: TArray<TPair<TPointD, TVectorD>>;
  VF3: TArray<GLr3v3c3v>;
  idx: Integer;
  VFD2: TVectorFieldDataR2;
  VFD3: TVectorFieldDataR3;
begin

  if Args.Count = 1 then
  begin

    var L := TArray<Double>(nil);
    var n := 0;

    Args.ExtractPointListRn(L, n);

    case n of
      3 + 3:
        begin
          SetLength(VF3, Length(L) div 6);
          for i := 0 to High(VF3) do
          begin
            VF3[i].r :=
              vec(
                L[6 * i + 0],
                L[6 * i + 1],
                L[6 * i + 2]
              );
            VF3[i].v :=
              vec(
                L[6 * i + 3],
                L[6 * i + 4],
                L[6 * i + 5]
              );
            VF3[i].c := rglv_black;
          end;
        end;
      3 + 3 + 1:
        begin
          SetLength(VF3, Length(L) div 7);
          for i := 0 to High(VF3) do
          begin
            VF3[i].r :=
              vec(
                L[7 * i + 0],
                L[7 * i + 1],
                L[7 * i + 2]
              );
            VF3[i].v :=
              vec(
                L[7 * i + 3],
                L[7 * i + 4],
                L[7 * i + 5]
              );
            VF3[i].c :=
              TColor(RBSwap(Round(
                L[7 * i + 6]
              )));
          end;
        end;
    else
      raise EInvArgs.Create('Each vector must be of dimension 6 (pos, vec) or 7 (pos, vec, colour).');
    end;

    VFD3 := TVectorFieldDataR3.Create;
    VFD3.Vectors := VF3;
    VFD3.Colored := n = 3 + 3 + 1;
    FVisual := TVisual.Create3D(vkVectorField, VFD3);

  end
  else
  begin
    const N = 20;
    zd := 0; z0 := 0; // W1036
    Args
      .Extract(F)
      .Extract(vx)
      .Extract(vy)
      .Extract(vz, ASR3(0, 0, 0))
      .Close;
    Dim := Args.Count - 1;
    if vx.Dimension in [2, 3] then
    begin
      x0 := vx[0];
      x1 := vx[1];
      Dx := x1 - x0;
      if vx.Dimension = 3 then
        xd := vx[2]
      else
        xd := Dx / N;
    end
    else
      ErrInvalidArguments;
    if vy.Dimension in [2, 3] then
    begin
      y0 := vy[0];
      y1 := vy[1];
      Dy := y1 - y0;
      if vy.Dimension = 3 then
        yd := vy[2]
      else
        yd := Dy / N;
    end
    else
      ErrInvalidArguments;
    if Dim = 3 then
    begin
      if vz.Dimension in [2, 3] then
      begin
        z0 := vz[0];
        z1 := vz[1];
        Dz := z1 - z0;
        if vz.Dimension = 3 then
          zd := vz[2]
        else
          zd := Dz / N;
      end
      else
        ErrInvalidArguments;
    end;
    if
      (Dx < 0)
        or
      (Dy < 0)
        or
      (Dim = 3) and (Dz < 0)
        or
      (xd <= 0)
        or
      (yd <= 0)
        or
      (Dim = 3) and (zd <= 0)
    then
      ErrInvalidArguments;
    xn := Floor(Dx / xd) + 1;
    yn := Floor(Dy / yd) + 1;
    if Dim = 3 then
      zn := Floor(Dz / zd) + 1
    else
      zn := 1;
    if xn < 1 then xn := 1;
    if yn < 1 then yn := 1;
    if zn < 1 then zn := 1;
    if (xn > 1E8) or (yn > 1E8) or (zn > 1E8) or (xn * yn * zn > 1E8) then
      raise EInvArgs.Create('Too great resolution.');
    case Dim of
      2:
        begin
          SetLength(VF2, xn * yn);
          idx := 0;
          for i := 0 to xn - 1 do
            for j := 0 to yn - 1 do
            begin
              x := x0 + i * xd;
              y := y0 + j * yd;
              try
                Obj := F.Execute(Context, [ASO(x), ASO(y)], True);
              except
                on E: ERuntimeException do
                  Continue;
              end;
              try
                w := Obj.AsRealVector;
                if w.Dimension <> 2 then
                  ErrInvalidArguments;
                VF2[idx] := TPair<TPointD, TVectorD>.Create(
                  TPointD.Create(x, y),
                  TVectorD.Create(w[0], w[1])
                );
                Inc(idx);
              finally
                Obj.Free;
              end;
            end;
          VFD2 := TVectorFieldDataR2.Create;
          VFD2.Vectors := VF2;
          FVisual := TVisual.Create2D(vkVectorField, VFD2,
            procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
            begin
              ACtl.View.&Set(x0 - 0.1*Dx, x1 + 0.1*Dx, y0 - 0.1*Dy, y1 + 0.1*Dy, True);
            end
          );
        end;
      3:
        begin
          var LColored := False;
          SetLength(VF3, xn * yn * zn);
          idx := 0;
          for i := 0 to xn - 1 do
            for j := 0 to yn - 1 do
              for k := 0 to zn - 1 do
              begin
                x := x0 + i * xd;
                y := y0 + j * yd;
                z := z0 + k * zd;
                try
                  Obj := F.Execute(Context, [ASO(x), ASO(y), ASO(z)], True);
                except
                  on E: Exception do
                    Continue;
                end;
                try
                  w := Obj.AsRealVector;
                  if not (w.Dimension in [3, 4]) then
                    ErrInvalidArguments;
                  VF3[idx].r := vec(x, y, z);
                  VF3[idx].v := vec(w[0], w[1], w[2]);
                  if w.Dimension = 4 then
                  begin
                    VF3[idx].c := TColor(RBSwap(Round(w[3])));
                    LColored := True;
                  end
                  else
                    VF3[idx].c := rglv_black;
                  Inc(idx);
                finally
                  Obj.Free;
                end;
              end;
          VFD3 := TVectorFieldDataR3.Create;
          VFD3.Vectors := VF3;
          VFD3.Colored := LColored;
          FVisual := TVisual.Create3D(vkVectorField, VFD3);
        end;
    end;
  end;

  inherited;

end;

{ FCN_RemoveVisual }

procedure FCN_RemoveVisual.SimpleFunction;
var
  GUID: TGUID;
begin
  Args.Extract(GUID).Close;
  if not Context.Perform(CLIENT_COMMAND_REMOVEVISUAL, NativeInt(@GUID)) then
    ClientVisErr;
end;

{ FCN_AdjustVisual }

procedure FCN_AdjustVisual.SimpleFunction;
var
  GUID: TGUID;
  Settings: TAlgosimStructure;
  Ref: TAlgosimReference;
begin

  if Args.Count = 1 then
  begin
    Args.MoveObject<TAlgosimReference>(Value, Ref).Close;
    GUID := Ref.GUID;
    Context.Perform(CLIENT_COMMAND_CONFIGVISUAL, NativeInt(@GUID));
    Exit;
  end;

  Settings := Args.MoveObject<TAlgosimReference>(Value, Ref).ExtractStruct;
  try
    GUID := Ref.GUID;
    Context.Perform(CLIENT_COMMAND_CONFIGVISUAL, NativeInt(@GUID), NativeInt(Settings));
  finally
    Settings.Free;
  end;

end;

{ FCN_LineSegment }

procedure FCN_LineSegment.SimpleFunction;
var
  a, b: TRealVector;
  LD: TLineDataR2;
begin
  Args.Extract(a).Extract(b).Close;
  LD := TLineDataR2.Create;
  LD.a := TPointD.Create(a);
  LD.b := TPointD.Create(b);
  FVisual := TVisual.Create2D(vkLine, LD);
  inherited;
end;

{ FCN_Rectangle }

procedure FCN_Rectangle.SimpleFunction;
var
  a: TRealVector;
  w, h: TASR;
  RD: TRectangleData;
begin
  Args.Extract(a).Extract(w).Extract(h, w).Close;
  RD := TRectangleData.Create;
  RD.a := TPointD.Create(a);
  RD.w := w;
  RD.h := h;
  FVisual := TVisual.Create2D(vkRectangle, RD);
  inherited;
end;

{ FCN_Circle }

procedure FCN_Circle.SimpleFunction;
var
  a: TRealVector;
  r: TASR;
  CD: TCircleData;
begin
  Args.Extract(a).ExtractPos(r, 1).Close;
  CD := TCircleData.Create;
  CD.a := TPointD.Create(a);
  CD.r := r;
  FVisual := TVisual.Create2D(vkCircle, CD,
    nil,
    procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
    begin
      with ADrawable as TGeometry do
        Style.Opacity := 0;
    end
  );
  inherited;
end;

{ FCN_Disk }

procedure FCN_Disk.SimpleFunction;
var
  a: TRealVector;
  r: TASR;
  CD: TCircleData;
begin
  Args.Extract(a).ExtractPos(r, 1).Close;
  CD := TCircleData.Create;
  CD.a := TPointD.Create(a);
  CD.r := r;
  FVisual := TVisual.Create2D(vkCircle, CD,
    nil,
    procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
    begin
      with ADrawable as TGeometry do
        Style.Opacity := Style.Opacity.MaxValue;
    end
  );
  inherited;
end;

{ FCN_Polygon }

procedure FCN_Polygon.SimpleFunction;
var
  L: TArray<TASR2>;
  PD: TPolygonData;
  RX, RY: TDataRange;
begin
  L := Args.ExtractPointsR2;
  PD := GetScatterDataR2(L, @RX, @RY);
  FVisual := TVisual.Create2D(vkPolygon, PD,
    procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
    begin
      ACtl.View.&Set(
        RX.Min - 0.1*RX.SpanOrUnit,
        RX.Max + 0.1*RX.SpanOrUnit,
        RY.Min - 0.1*RY.SpanOrUnit,
        RY.Max + 0.1*RY.SpanOrUnit,
        True
      );
    end
  );
  inherited;
end;

{ FCN_Text }

procedure FCN_Text.SimpleFunction;
var
  a, d: TRealVector;
  α: TASR;
  s: string;
  TD: TTextData;
begin
  Args
    .Extract(a)
    .Extract(s)
    .Extract(d, ASR3(0, 0, 1))
    .Extract(α, 0.0)
    .Close;
  var Dim := a.Dimension;
  if not (Dim in [2, 3]) then
    ErrInvalidArguments;
  case Dim of
    2:
      begin
        TD := TTextData.Create;
        TD.Position := TPointD.Create(a);
        TD.Text := s;
        FVisual := TVisual.Create2D(vkText, TD);
      end;
    3:
      begin
        TD := TTextData.Create;
        TD.Text := s;
        FVisual := TVisual.Create3D(vkText, TD, nil,
          procedure(ACtl: TVisCtl3D; ADrawable: TDrawable3D)
          begin
            (ADrawable as TGeometricObject3D).Position := a;
            (ADrawable as TGeometricObject3D).Direction := d;
            (ADrawable as TGeometricObject3D).Rotation := α;
          end
        );
      end;
  end;
  inherited;
end;

{ FCN_EmbedPixmap }

procedure FCN_EmbedPixmap.SimpleFunction;
var
  a, d: TRealVector;
  w, h, α: TASR;
  pm: TASPixmap;
begin
  Args
    .Extract(pm)
    .Extract(a)
    .ExtractPos(w, 10.0)
    .ExtractNonNeg(h, 0.0)
    .Extract(d, ASR3(0, 0, 1))
    .Extract(α, 0.0)
    .Close;
  var Dim := a.Dimension;
  if not (Dim in [2, 3]) or (pm.Width = 0.0) then
    ErrInvalidArguments;
  if h = 0.0 then
    h := w * pm.Height / pm.Width;
  case Dim of
    2:
      begin
        var PD := TPixmapData.Create;
        PD.Rect := TRectD.Create(a[0], a[1] - h, a[0] + w, a[1]);
        PD.Pixmap := pm;
        FVisual := TVisual.Create2D(vkPixmap, PD);
      end;
    3:
      begin
        var PD := TPixmapData.Create;
        PD.Pixmap := pm;
        FVisual := TVisual.Create3D(vkPixmap, PD, nil,
          procedure(ACtl: TVisCtl3D; ADrawable: TDrawable3D)
          begin
            (ADrawable as TGeometricObject3D).Position := a;
            (ADrawable as TGeometricObject3D).Scale := vec(1, w, h);
            (ADrawable as TGeometricObject3D).Direction := d;
            (ADrawable as TGeometricObject3D).Rotation := α;
          end
        );
      end;
  end;
  inherited;
end;

{ FCN_Speak }

procedure FCN_Speak.SimpleFunction;
var
  Obj: TAlgosimObject;
begin
  inherited;
  Args.Extract(Obj).Close;
  with TASSpeech.Create do
    try
      Speak(
        Obj.ToSpeech,
        Context.AbortCurrentEvent.Handle,
        Context.EnterPauseEvent.Handle,
        procedure
        begin
          ManualAbort;
        end,
        procedure
        begin
          if DoPause(Context.ResumeEvent, Context.AbortCurrentEvent) = raAbort then
            ManualAbort;
        end
      )
    finally
      Free;
    end;
end;

{ FCN_Surface }

procedure FCN_Surface.DoExecute;
begin

  if
    (ChildCount >= 1)
      and
    (Children[0] is FCN_Apply)
  then
  begin

    //
    // Parameterised surface
    //

    if
      (ChildCount = 0)
        or
      not (Children[0] is FCN_Apply)
        or
      (Children[0].ChildCount <> 2)
        or
      not (Children[0].Children[0] is FCN_Cross)
        or
      (Children[0].Children[0].ChildCount <> 2)
        or
      not (Children[0].Children[0].Children[0] is FCN_ClosedInterval)
        or
      not (Children[0].Children[0].Children[1] is FCN_ClosedInterval)
        or
      not (Children[0].Children[0].Children[0].ChildCount in [2, 3])
        or
      not (Children[0].Children[0].Children[1].ChildCount in [2, 3])
    then
      raise EInvArgs.Create('Expected a parameterised surface of the form [a, b] × [c, d] @ F.');

    const expr_apply = Children[0];
    const expr_cross = expr_apply.Children[0];
    const expr_udom = expr_cross.Children[0];
    const expr_udommin = expr_udom.Children[0];
    const expr_udommax = expr_udom.Children[1];
    const expr_vdom = expr_cross.Children[1];
    const expr_vdommin = expr_vdom.Children[0];
    const expr_vdommax = expr_vdom.Children[1];
    const expr_fcn = expr_apply.Children[1];

    expr_udommin.Evaluate;
    expr_udommax.Evaluate;
    expr_vdommin.Evaluate;
    expr_vdommax.Evaluate;
    expr_fcn.Evaluate;

    var uminobj := expr_udommin.Value; CheckFailure(uminobj);
    var umaxobj := expr_udommax.Value; CheckFailure(umaxobj);
    var vminobj := expr_vdommin.Value; CheckFailure(vminobj);
    var vmaxobj := expr_vdommax.Value; CheckFailure(vmaxobj);
    var fcnobj := expr_fcn.Value; CheckFailure(fcnobj);

    var umin := uminobj.ToASR;
    var umax := umaxobj.ToASR;
    var vmin := vminobj.ToASR;
    var vmax := vmaxobj.ToASR;

    var fcn := fcnobj as TAlgosimFunctionObject;

    var udelta := TASR(0);
    if expr_udom.ChildCount >= 3 then
    begin
      const expr_udomdelta = expr_udom.Children[2];
      expr_udomdelta.Evaluate;
      var udomdeltaobj := expr_udomdelta.Value; CheckFailure(udomdeltaobj);
      udelta := udomdeltaobj.ToASR;
    end;

    var vdelta := TASR(0);
    if expr_vdom.ChildCount >= 3 then
    begin
      const expr_vdomdelta = expr_vdom.Children[2];
      expr_vdomdelta.Evaluate;
      var vdomdeltaobj := expr_vdomdelta.Value; CheckFailure(vdomdeltaobj);
      vdelta := vdomdeltaobj.ToASR;
    end;

    var Nu := 257;
    var Nv := 257;

    if udelta <> 0 then
    begin
      Nu := Ceil((umax - umin) / udelta) + 1;
      if (Nu < 2) or (Nu > 8192) then
        raise EInvArgs.Create('Invalid resolution in the first variable.');
    end;

    if vdelta <> 0 then
    begin
      Nv := Ceil((vmax - vmin) / vdelta) + 1;
      if (Nv < 2) or (Nv > 8192) then
        raise EInvArgs.Create('Invalid resolution in the second variable.');
    end;

    udelta := (umax - umin) / (Nu - 1);
    vdelta := (vmax - vmin) / (Nv - 1);

    var L3 :=  TList<TASR3>.Create;
    try
      var L4 := TList<TASR4>.Create;
      try

        for var j := 0 to Nv - 1 do
        begin
          var v := vmin + j * vdelta;
          for var i := 0 to Nu - 1 do
          begin
            var u := umin + i * udelta;
            var res := fcn.Execute(Context, [ASO(u), ASO(v)], True);
            try
              if res is TAlgosimVector then
              begin
                var img := res.AsRealVector;
                if img.Dimension = 3 then
                  L3.Add(TASR3.Create(img[0], img[1], img[2]))
                else if img.Dimension = 4 then
                  L4.Add(TASR4.Create(img[0], img[1], img[2], img[3]))
                else
                  raise EInvArgs.Create('Surface parameterisation function must return a three- or four-dimensional real vector.');
              end
              else
                raise EInvArgs.Create('Surface parameterisation function must return a three- or four-dimensional real vector.');
            finally
              res.Free;
            end;
          end;
        end;

        if (L3.Count > 0) and (L4.Count > 0) then
          raise EInvArgs.Create('The surface parameterisation function returned some three-dimensional vectors and some four-dimensional vectors.');

        var SurfData: TObject := nil;
        if L4.Count > 0 then
          SurfData := GetColoredSurfaceData(L4.ToArray, umin, umax, Nu, vmin, vmax, Nv)
        else
          SurfData := GetSurfaceData(L3.ToArray, umin, umax, Nu, vmin, vmax, Nv);
        var Visual := TVisual.Create3D(vkSurface, SurfData);
        try
          var Ref: TAlgosimReference := nil;
          if
            Context.Perform(CLIENT_COMMAND_ADDVISUAL, NativeInt(Visual), NativeInt(@Ref))
              and
            Assigned(Ref)
          then
            Result := Ref
          else
            ClientVisErr;
        finally
          Visual.Free;
        end;

      finally
        L4.Free;
      end;
    finally
      L3.Free;
    end;

  end
  else
  begin

    //
    // Equation of the form z = expr in x and y (cycl.)
    //

    if
      (ChildCount = 0)
        or
      not (Children[0] is FCN_Equals)
        or
      (Children[0].ChildCount <> 2)
        or
      not IsSymbolAny(Children[0].Children[0], ['x', 'y', 'z'])
    then
      raise EInvArgs.Create('The surface must be specified of the form z = expression in x and y or any permutation thereof.');

    const LFcnExpr = Children[0].Children[1];

    const LHS = (Children[0].Children[0] as TASSymbolExprNode).Symbol;

    var uparams, vparams: TRealVector;
    var umin, umax, udelta, vmin, vmax, vdelta: TASR;

    var LColorExpr := TASExprNode(nil);

    case Args.Count of
      1:
        Args.Skip.Close;
      3:
        begin
          if not EvalChildren(1) then Exit;
          Args
            .Skip
            .Extract(uparams)
            .Extract(vparams)
            .Close
        end;
      4:
        begin
          if not EvalChild(1) then Exit;
          if not EvalChild(2) then Exit;
          Args
            .Skip
            .Extract(uparams)
            .Extract(vparams)
            .Skip
            .Close;
          LColorExpr := Children[3];
        end;
    end;

    if not (uparams.Dimension in [0, 2, 3]) or ((uparams.Dimension >= 2) and (uparams[0] >= uparams[1])) then
      raise EInvArgs.Create('Invalid domain specification in the first variable.');

    if not (vparams.Dimension in [0, 2, 3]) or ((vparams.Dimension >= 2) and (vparams[0] >= vparams[1])) then
      raise EInvArgs.Create('Invalid domain specification in the second variable.');

    umin := -10; umax := 10; udelta := 0;
    if uparams.Dimension >= 2 then
    begin
      umin := uparams[0];
      umax := uparams[1];
      if uparams.Dimension >= 3 then
        udelta := uparams[2];
    end;

    vmin := -10; vmax := 10; vdelta := 0;
    if vparams.Dimension >= 2 then
    begin
      vmin := vparams[0];
      vmax := vparams[1];
      if vparams.Dimension >= 3 then
        vdelta := vparams[2];
    end;

    var Nu := 257;
    var Nv := 257;

    if udelta <> 0 then
    begin
      Nu := Ceil((umax - umin) / udelta) + 1;
      if (Nu < 2) or (Nu > 8192) then
        raise EInvArgs.Create('Invalid resolution in the first variable.');
    end;

    if vdelta <> 0 then
    begin
      Nv := Ceil((vmax - vmin) / vdelta) + 1;
      if (Nv < 2) or (Nv > 8192) then
        raise EInvArgs.Create('Invalid resolution in the second variable.');
    end;

    udelta := (umax - umin) / (Nu - 1);
    vdelta := (vmax - vmin) / (Nv - 1);

    const Coords: TArray<string> = ['x', 'y', 'z'];

    const LHSIndex = IndexStr(LHS, Coords);

    const uIndex = (LHSIndex + 1) mod 3;
    const vIndex = (LHSIndex + 2) mod 3;
    const wIndex = LHSIndex;

    if LHSIndex = -1 then
      raise EInvArgs.Create('Unsupported LHS symbol.');

    const usymbol = Coords[uIndex];
    const vsymbol = Coords[vIndex];
    const wsymbol = Coords[wIndex];

    var L3 := TList<TASR3>.Create;
    try
      var L4 := TList<TASR4>.Create;
      try

        var w: TASR;
        var P3: TASR3;
        var P4: TASR4;
        var symbols_u := TList<TASExprNode>.Create;
        try
          FindSymbols(LFcnExpr, usymbol, symbols_u);
          FindSymbols(LColorExpr, usymbol, symbols_u);
          var symbols_v := TList<TASExprNode>.Create;
          try
            FindSymbols(LFcnExpr, vsymbol, symbols_v);
            FindSymbols(LColorExpr, vsymbol, symbols_v);
            var symbols_w := TList<TASExprNode>.Create;
            try
              FindSymbols(LColorExpr, wsymbol, symbols_w);
              for var j := 0 to Nv - 1 do
              begin
                var v := vmin + j * vdelta;
                PopulateSymbols(symbols_v, ASO(v));
                for var i := 0 to Nu - 1 do
                begin
                  var u := umin + i * udelta;
                  PopulateSymbols(symbols_u, ASO(u));
                  LFcnExpr.Evaluate;
                  var res := LFcnExpr.Value;
                  CheckFailure(res);
                  if not res.TryToASR(w) then
                    w := NaN;
                  if Assigned(LColorExpr) then
                  begin
                    if symbols_w.Count > 0 then
                      PopulateSymbols(symbols_w, ASO(w));
                    var cval: TColor := clBlack;
                    if not IsNan(w) then
                    begin
                      LColorExpr.Evaluate;
                      var cres := LColorExpr.Value;
                      CheckFailure(cres);
                      cval := RBSwap(cres.ToColor);
                    end;
                    P4.Elems[uIndex] := u;
                    P4.Elems[vIndex] := v;
                    P4.Elems[LHSIndex] := w;
                    P4.W := cval;
                    L4.Add(P4);
                  end
                  else
                  begin
                    P3.Elems[uIndex] := u;
                    P3.Elems[vIndex] := v;
                    P3.Elems[LHSIndex] := w;
                    L3.Add(P3);
                  end;
                end;
              end;
            finally
              symbols_w.Free;
            end;
          finally
            symbols_v.Free;
          end;
        finally
          symbols_u.Free;
        end;

        var SurfData: TObject := nil;
        if Assigned(LColorExpr) then
          SurfData := GetColoredSurfaceData(L4.ToArray, umin, umax, Nu, vmin, vmax, Nv)
        else
          SurfData := GetSurfaceData(L3.ToArray, umin, umax, Nu, vmin, vmax, Nv);

        var Visual := TVisual.Create3D(vkSurface, SurfData);
        try
          var Ref: TAlgosimReference := nil;
          if
            Context.Perform(CLIENT_COMMAND_ADDVISUAL, NativeInt(Visual), NativeInt(@Ref))
              and
            Assigned(Ref)
          then
            Result := Ref
          else
            ClientVisErr;
        finally
          Visual.Free;
        end;

      finally
        L4.Free;
      end;
    finally
      L3.Free;
    end;

  end;

end;

{ FCN_Curve }

procedure FCN_Curve.SimpleFunction;
var
  List: TArray<Double>;
  RX, RY, RZ: TDataRange;
begin
  var n := 0;
  Args.ExtractPointListRn(List, n);
  case n of
    2:
      begin
        var SD := GetScatterDataR2(DoubleListToASR2s(List), @RX, @RY);
        FVisual := TVisual.Create2D(vkXYPlot, SD,
          procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
          var
            A, B: Double;
          begin
            A := RY.Min - 0.1*RY.Span;
            B := RY.Max + 0.1*RY.Span;
            ACtl.View.&Set(RX.Min - 0.1*RX.Span, RX.Max + 0.1*RX.Span, A, B, True);
          end,
          procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
          begin
            with ADrawable as TXYPlot do
            begin
              Points := False;
              PointSize := 6;
              Lines := True;
            end;
          end
        );
      end;
    3:
      begin
        var SD := GetCurveDataR3(DoubleListToASR3s(List), @RX, @RY, @RZ);
        FVisual := TVisual.Create3D(vkSpaceCurve, SD);
      end;
    4:
      begin
        var SD := GetCurveDataR3cs(List, @RX, @RY, @RZ);
        FVisual := TVisual.Create3D(vkSpaceCurve, SD);
      end
  else
    raise EInvArgs.Create('Data to plot must be of the form (x, y), (x, y, z), or (x, y, z, color).');
  end;

  inherited;
end;

{ FCN_Sphere }

procedure FCN_Sphere.SimpleFunction;
var
  a: TRealVector;
  r: TASR;
begin
  Args.Extract(a, ASR3(0, 0, 0)).ExtractPos(r, 1).Close;
  FVisual := TVisual.Create3D(vkObject3D, O3D(TSphere), nil,
    procedure(ACtl: TVisCtl3D; ADrawable: TDrawable3D)
    begin
      (ADrawable as TSphere).Position := a;
      (ADrawable as TSphere).Radius := r;
    end
  );
  inherited;
end;

{ FCN_Ellipsoid }

procedure FCN_Ellipsoid.SimpleFunction;
var
  a, f, d: TRealVector;
  α: TASR;
begin
  Args
    .Extract(a, ASR3(0, 0, 0))
    .Extract(f, ASR3(1, 2, 3))
    .Extract(d, ASR3(0, 0, 1))
    .Extract(α, 0.0)
    .Close;
  FVisual := TVisual.Create3D(vkObject3D, O3D(TEllipsoid), nil,
    procedure(ACtl: TVisCtl3D; ADrawable: TDrawable3D)
    begin
      (ADrawable as TGeometricObject3D).Position := a;
      (ADrawable as TGeometricObject3D).Scale := f;
      (ADrawable as TGeometricObject3D).Direction := d;
      (ADrawable as TGeometricObject3D).Rotation := α;
    end
  );
  inherited;
end;

{ FCN_Cylinder }

procedure FCN_Cylinder.SimpleFunction;
var
  a, f, d: TRealVector;
  α: TASR;
begin
  Args
    .Extract(a, ASR3(0, 0, 0))
    .Extract(f, ASR3(1, 1, 1))
    .Extract(d, ASR3(0, 0, 1))
    .Extract(α, 0.0)
    .Close;
  FVisual := TVisual.Create3D(vkObject3D, O3D(TCylinder), nil,
    procedure(ACtl: TVisCtl3D; ADrawable: TDrawable3D)
    begin
      (ADrawable as TGeometricObject3D).Position := a;
      (ADrawable as TGeometricObject3D).Scale := f;
      (ADrawable as TGeometricObject3D).Direction := d;
      (ADrawable as TGeometricObject3D).Rotation := α;
    end
  );
  inherited;
end;

{ FCN_Cone }

procedure FCN_Cone.SimpleFunction;
var
  a, f, d: TRealVector;
  α: TASR;
begin
  Args
    .Extract(a, ASR3(0, 0, 0))
    .Extract(f, ASR3(1, 1, 1))
    .Extract(d, ASR3(0, 0, 1))
    .Extract(α, 0.0)
    .Close;
  FVisual := TVisual.Create3D(vkObject3D, O3D(TCone), nil,
    procedure(ACtl: TVisCtl3D; ADrawable: TDrawable3D)
    begin
      (ADrawable as TGeometricObject3D).Position := a;
      (ADrawable as TGeometricObject3D).Scale := f;
      (ADrawable as TGeometricObject3D).Direction := d;
      (ADrawable as TGeometricObject3D).Rotation := α;
    end
  );
  inherited;
end;

{ FCN_Plane }

procedure FCN_Plane.SimpleFunction;
var
  a, f, d: TRealVector;
  α: TASR;
begin
  Args
    .Extract(a, ASR3(0, 0, 0))
    .Extract(f, ASR3(1, 1, 1))
    .Extract(d, ASR3(0, 0, 1))
    .Extract(α, 0.0)
    .Close;
  FVisual := TVisual.Create3D(vkObject3D, O3D(TPlane), nil,
    procedure(ACtl: TVisCtl3D; ADrawable: TDrawable3D)
    begin
      (ADrawable as TGeometricObject3D).Position := a;
      (ADrawable as TGeometricObject3D).Scale := f;
      (ADrawable as TGeometricObject3D).Direction := d;
      (ADrawable as TGeometricObject3D).Rotation := α;
    end
  );
  inherited;
end;

{ FCN_InfinatePlane }

procedure FCN_InfinatePlane.SimpleFunction;
var
  a, d: TRealVector;
begin
  Args
    .Extract(a, ASR3(0, 0, 0))
    .Extract(d, ASR3(0, 0, 1))
    .Close;
  FVisual := TVisual.Create3D(vkObject3D, O3D(TInfinitePlane), nil,
    procedure(ACtl: TVisCtl3D; ADrawable: TDrawable3D)
    begin
      (ADrawable as TGeometricObject3D).Position := a;
      (ADrawable as TGeometricObject3D).Direction := d;
    end
  );
  inherited;
end;

{ FCN_Disk3D }

procedure FCN_Disk3D.SimpleFunction;
var
  a, f, d: TRealVector;
  α: TASR;
begin
  Args
    .Extract(a, ASR3(0, 0, 0))
    .Extract(f, ASR3(1, 1, 1))
    .Extract(d, ASR3(0, 0, 1))
    .Extract(α, 0.0)
    .Close;
  FVisual := TVisual.Create3D(vkObject3D, O3D(TDisk), nil,
    procedure(ACtl: TVisCtl3D; ADrawable: TDrawable3D)
    begin
      (ADrawable as TGeometricObject3D).Position := a;
      (ADrawable as TGeometricObject3D).Scale := f;
      (ADrawable as TGeometricObject3D).Direction := d;
      (ADrawable as TGeometricObject3D).Rotation := α;
    end
  );
  inherited;
end;

{ FCN_Solid }

procedure FCN_Solid.SimpleFunction;
var
  s: string;
  a, f, d: TRealVector;
  α: TASR;
begin
  Args
    .Extract(s)
    .Extract(a, ASR3(0, 0, 0))
    .Extract(f, ASR3(1, 1, 1))
    .Extract(d, ASR3(0, 0, 1))
    .Extract(α, 0.0)
    .Close;
  FVisual := TVisual.Create3D(vkObject3D, O3D(s), nil,
    procedure(ACtl: TVisCtl3D; ADrawable: TDrawable3D)
    begin
      (ADrawable as TGeometricObject3D).Position := a;
      (ADrawable as TGeometricObject3D).Scale := f;
      (ADrawable as TGeometricObject3D).Direction := d;
      (ADrawable as TGeometricObject3D).Rotation := α;
    end
  );
  inherited;
end;

{ FCN_Model }

procedure FCN_Model.SimpleFunction;
var
  s: string;
  a, f, d: TRealVector;
  α: TASR;
begin
  Args
    .Extract(s)
    .Extract(a, ASR3(0, 0, 0))
    .Extract(f, ASR3(1, 1, 1))
    .Extract(d, ASR3(0, 0, 1))
    .Extract(α, 0.0)
    .Close;
  FVisual := TVisual.Create3D(vkObject3D, O3D(TObjModel, '', s), nil,
    procedure(ACtl: TVisCtl3D; ADrawable: TDrawable3D)
    begin
      (ADrawable as TGeometricObject3D).Position := a;
      (ADrawable as TGeometricObject3D).Scale := f;
      (ADrawable as TGeometricObject3D).Direction := d;
      (ADrawable as TGeometricObject3D).Rotation := α;
    end
  );
  inherited;
end;

{ FCN_CoordinateAxes }

procedure FCN_CoordinateAxes.SimpleFunction;
var
  a, u, v, w: TRealVector;
begin
  Args
    .Extract(a, ASR3(0, 0, 0))
    .Extract(u, ASR3(1, 0, 0))
    .Extract(v, ASR3(0, 1, 0))
    .Extract(w, ASR3(0, 0, 1))
    .Close;
  FVisual := TVisual.Create3D(vkObject3D, O3D(TAxes), nil,
    procedure(ACtl: TVisCtl3D; ADrawable: TDrawable3D)
    begin
      (ADrawable as TGeometricObject3D).ManualMatrix := rglTranslate(a) * rglm4(rglm.CreateFromColumns(u, v, w));
      (ADrawable as TGeometricObject3D).UseManualMatrix := True;
    end
  );
  inherited;
end;

{ FCN_Clamp }

procedure FCN_Clamp.SimpleFunction;
var
  X, A, B: TASR;
begin
  Args.Extract(X).Extract(A).Extract(B).Close;
  if A > B then
    Result := ASO(A)
  else
    Result := ASO(EnsureRange(X, A, B));
end;

{ FCN_Paste }

procedure FCN_Paste.SimpleFunction;
begin
  if Clipboard.HasFormat(CF_BITMAP) then
  begin
    var bm := Graphics.TBitmap.Create;
    try
      bm.LoadFromClipboardFormat(CF_BITMAP, Clipboard.GetAsHandle(CF_BITMAP), 0);
      bm.PixelFormat := pf32bit;
      Result := ASO(TASPixmap.Create(bm));
    finally
      bm.Free;
    end;
  end
  else if Clipboard.HasFormat(CF_TEXT) then
    Result := ASO(Clipboard.AsText)
  else if Clipboard.HasFormat(CF_WAVE) then
  begin
    var MS := TMemoryStream.Create;
    try
      Clipboard.Open;
      try
        var h := Clipboard.GetAsHandle(CF_WAVE);
        if h = 0 then
          Exit;
        var p := GlobalLock(h);
        if p = nil then
          RaiseLastOSError;
        try
          MS.SetSize(GlobalSize(h));
          MS.Position := 0;
          CopyMemory(MS.Memory, p, MS.Size);
        finally
          GlobalUnlock(h);
        end;
      finally
        Clipboard.Close;
      end;
      Result := ASO(LoadSoundFromStream(MS));
    finally
      MS.Free;
    end;
  end;
end;

{ FCN_ClearScene }

procedure FCN_ClearScene.SimpleFunction;
var
  Name: string;
  Ref: TAlgosimReference;
begin
  Args.Extract(Name, '').Close;
  Ref := nil;
  if
    Context.Perform(CLIENT_COMMAND_CLEARSCENE, NativeInt(PChar(Name)), NativeInt(@Ref))
  then
    Result := Ref
  else
    ClientVisErr;
end;

{ FCN_ClearDiagram }

procedure FCN_ClearDiagram.SimpleFunction;
var
  Name: string;
  Ref: TAlgosimReference;
begin
  Args.Extract(Name, '').Close;
  Ref := nil;
  if
    Context.Perform(CLIENT_COMMAND_CLEARDIAGRAM, NativeInt(PChar(Name)), NativeInt(@Ref))
  then
    Result := Ref
  else
    ClientVisErr;
end;

{ FCN_VisualObject }

procedure FCN_VisualObject.SimpleFunction;

  function Declassify(const S: string): string;
  begin
    if (S <> '') and (S[1] = 'T') then
      Result := Copy(S, 2)
    else
      Result := S;
  end;

begin
  var Ref: TAlgosimReference;
  Args.Extract(Ref).Close;
  var R := TVisualRec.Create;
  try
    R.ID := Ref.GUID;
    if Context.Perform(CLIENT_COMMAND_QUERYVISOBJ, NativeInt(R)) then
    begin
      if R.ClassType <> nil then
        Result :=
          ASOVisObject(
            R.ID,
            R.Name,
            Declassify(R.ClassType.ClassName),
            R.ClassType.GetRealm,
            R.Title,
            R.Description,
            R.LastPaintTime
          )
      else
        ClientVisErr;
    end;
  finally
    R.Free;
  end;
end;

{ FCN_VisualObjects }

procedure FCN_VisualObjects.SimpleFunction;
begin
  Args.Close;
  var L := TList<TGUID>.Create;
  try
    if Context.Perform(CLIENT_COMMAND_ENUMVISOBJ, NativeInt(L)) then
      Result := TAlgosimArray.CreateWithValue(L.ToArray)
    else
      ClientVisErr;
  finally
    L.Free;
  end;
end;

{ FCN_MemoryUsage }

procedure FCN_MemoryUsage.SimpleFunction;
begin
  Args.Close;
  var PMC := Default(TProcessMemoryCounters);
  PMC.cb := SizeOf(PMC);
  if GetProcessMemoryInfo(GetCurrentProcess, @PMC, SizeOf(PMC)) then
    Result := TAlgosimStructure.CreateWithValue(
      [
        sm('PageFaultCount', ASOInt(PMC.PageFaultCount, 10, True)),
        sm('PeakWorkingSetSize', ASOInt(PMC.PeakWorkingSetSize, 10, True)),
        sm('WorkingSetSize', ASOInt(PMC.WorkingSetSize, 10, True)),
        sm('QuotaPeakPagedPoolUsage', ASOInt(PMC.QuotaPeakPagedPoolUsage, 10, True)),
        sm('QuotaPagedPoolUsage', ASOInt(PMC.QuotaPagedPoolUsage, 10, True)),
        sm('QuotaPeakNonPagedPoolUsage', ASOInt(PMC.QuotaPeakNonPagedPoolUsage, 10, True)),
        sm('QuotaNonPagedPoolUsage', ASOInt(PMC.QuotaNonPagedPoolUsage, 10, True)),
        sm('PagefileUsage', ASOInt(PMC.PagefileUsage, 10, True)),
        sm('PeakPagefileUsage', ASOInt(PMC.PeakPagefileUsage, 10, True))
      ]
    )
  else
    RaiseLastOSError;
end;

{ FCN_Arrow }

procedure FCN_Arrow.SimpleFunction;
var
  a, b, v: TRealVector;
  prep: string;
begin

  case Args.Count of
    1:
      begin
        Args.Extract(v).Close;
        a := ZeroVector(v.Dimension);
        b := a + v;
      end;
    2:
      begin
        Args.Extract(a).Extract(v).Close;
        b := a + v;
      end;
    3:
      begin
        Args.Extract(a).Extract(prep).Extract(b).Close;
        if not SameText(prep, 'to') then
          ErrInvalidArguments;
        v := b - a;
      end;
  else
    ErrInvalidArguments;
  end;

  case a.Dimension of
    2:
      FVisual := TVisual.Create2D(vkArrow, GetArrowDataR2(a, v));
    3:
      FVisual := TVisual.Create3D(vkArrow, GetArrowDataR3(a, v));
  else
    ErrInvalidArguments;
  end;

  inherited;

end;

{ FCN_Roman }

procedure FCN_Roman.SimpleFunction;
begin

  if Args.PeekAt(0) is TAlgosimString then
  begin
    var S: string;
    Args.Extract(S).Close;
    Result := ASOInt(RomanToInt(S));
  end
  else
  begin
    var N: TASI;
    Args.Extract(N).Close;
    Result := ASOInt(N, fsRoman);
  end;

end;

{ FCN_ParseDate }

procedure FCN_ParseDate.SimpleFunction;

const
  ValidOrders:
    array[0..8] of string
      =
    (
      'ymd',
      'ydm',
      'myd',
      'mdy',
      'dmy',
      'dym',
      'ym',
      'my',
      'y'
    );

var
  S: string;

  procedure Err;
  begin
    raise EConvertError.CreateFmt('Incompatible date string "%s".', [S]);
  end;

begin

  var Parts := '';
  var Values := TArray<Integer>.Create(1, 1, 1);

  Args.Extract(S).Extract(Parts, ValidOrders, 'ymd').Close;

  var p := 0;
  var InNum := False;
  var NumStart := 0;
  for var i := 1 to S.Length + 1 do
  begin
    if InNum then
    begin
      if (i > S.Length) or not InRange(Ord(s[i]), Ord('0'), Ord('9')) then
      begin
        if p = Parts.Length then
          Err;
        const NumEnd = Pred(i);
        Values['ymd'.IndexOf(Parts[p + 1])] := StrToInt(Copy(S, NumStart, NumEnd - NumStart + 1));
        Inc(p);
        InNum := False;
      end;
    end
    else
    begin
      if (i <= S.Length) and InRange(Ord(s[i]), Ord('0'), Ord('9')) then
      begin
        InNum := True;
        NumStart := i;
      end;
    end;
  end;

  if p <> Parts.Length then
    Err;

  if not IsValidDate(Values[0], Values[1], Values[2]) then
    Err;

  Result := ASODate(Values[0], Values[1], Values[2]);

end;

{ FCN_ParseTime }

procedure FCN_ParseTime.SimpleFunction;

var
  S: string;

  procedure Err;
  begin
    raise EConvertError.CreateFmt('Incompatible time string "%s".', [S]);
  end;

begin

  Args.Extract(S).Close;

  var Values := TArray<Integer>.Create(00, 00, 00, 000);

  var p := 0;
  var InNum := False;
  var NumStart := 0;
  for var i := 1 to S.Length + 1 do
  begin
    if InNum then
    begin
      if (i > S.Length) or not InRange(Ord(s[i]), Ord('0'), Ord('9')) then
      begin
        if p = Length(Values) then
          Err;
        const NumEnd = Pred(i);
        Values[p] := StrToInt(Copy(S, NumStart, NumEnd - NumStart + 1));
        Inc(p);
        InNum := False;
      end;
    end
    else
    begin
      if (i <= S.Length) and InRange(Ord(s[i]), Ord('0'), Ord('9')) then
      begin
        InNum := True;
        NumStart := i;
      end;
    end;
  end;

  const LS = S.ToLower;
  if LS.Contains('pm') or LS.Contains('p.m.') or LS.Contains('p. m.') then
    Values[0] := Values[0] + 12;

  if p = 0 then
    Err;

  if not IsValidTime(Values[0], Values[1], Values[2], Values[3]) then
    Err;

  Result := ASOTime(Values[0], Values[1], Values[2], Values[3]);

end;

{ FCN_ParseDateTime }

procedure FCN_ParseDateTime.SimpleFunction;

  procedure ValidatePartSpec(const Parts: string);

    procedure Err;
    begin
      raise EConvertError.CreateFmt('Invalid part specification: "%s".', [Parts]);
    end;

  var
    Chars: array['a'..'z'] of Boolean;
  const
    ValidChars: set of AnsiChar = ['y', 'm', 'd', 'h', 'n', 's', 'z'];
  begin
    FillChar(Chars, SizeOf(Chars), 0);
    for var Char in Parts do
    begin
      if CharInSet(Char, ValidChars) then
      begin
        if Chars[Char] then
          Err
        else
          Chars[Char] := True;
      end
      else
        Err;
    end;
  end;

var
  S: string;

  procedure Err;
  begin
    raise EConvertError.CreateFmt('Incompatible datetime string "%s".', [S]);
  end;

begin

  var Parts := '';
  var Values := TArray<Integer>.Create(1, 1, 1, 00, 00, 00, 0000);

  Args.Extract(S).Extract(Parts, 'ymdhnsz').Close;

  ValidatePartSpec(Parts);

  var p := 0;
  var InNum := False;
  var NumStart := 0;
  for var i := 1 to S.Length + 1 do
  begin
    if InNum then
    begin
      if (i > S.Length) or not InRange(Ord(s[i]), Ord('0'), Ord('9')) then
      begin
        if p = Parts.Length then
          Err;
        const NumEnd = Pred(i);
        Values['ymdhnsz'.IndexOf(Parts[p + 1])] := StrToInt(Copy(S, NumStart, NumEnd - NumStart + 1));
        Inc(p);
        InNum := False;
      end;
    end
    else
    begin
      if (i <= S.Length) and InRange(Ord(s[i]), Ord('0'), Ord('9')) then
      begin
        InNum := True;
        NumStart := i;
      end;
    end;
  end;

  const LS = S.ToLower;
  if LS.Contains('pm') or LS.Contains('p.m.') or LS.Contains('p. m.') then
    Values[3] := Values[3] + 12;

  if not IsValidDateTime(Values[0], Values[1], Values[2], Values[3], Values[4], Values[5], Values[6]) then
    Err;

  Result := ASODateTime(Values[0], Values[1], Values[2], Values[3], Values[4], Values[5], Values[6]);

end;

{ FCN_Deltas }

procedure FCN_Deltas.SimpleFunction;
begin

  var Obj: TAlgosimObject;
  Args.Extract(Obj).Close;

  if Obj is TAlgosimArray then
  begin
    if (Obj.ElementCount > 0) and (Obj.Elements[1] is TAlgosimMatrix) then
    begin
      for var i := 1 to Obj.ElementCount do
        if not (Obj.Elements[i] is TAlgosimMatrix) then
          ErrInvalidArguments;
      Result := TAlgosimArray.CreateUninitialized(Max(0, Obj.ElementCount - 1));
      for var i := 2 to Obj.ElementCount do
        Result.Elements[i - 1] := TAlgosimMatrix.Subtract(TAlgosimMatrix(Obj.Elements[i]), TAlgosimMatrix(Obj.Elements[Pred(i)]));
    end
    else if (Obj.ElementCount > 0) and (Obj.Elements[1] is TAlgosimVector) then
    begin
      for var i := 1 to Obj.ElementCount do
        if not (Obj.Elements[i] is TAlgosimVector) then
          ErrInvalidArguments;
      Result := TAlgosimArray.CreateUninitialized(Max(0, Obj.ElementCount - 1));
      for var i := 2 to Obj.ElementCount do
        Result.Elements[i - 1] := TAlgosimVector.Subtract(TAlgosimVector(Obj.Elements[i]), TAlgosimVector(Obj.Elements[Pred(i)]));
    end
    else
    begin
      for var i := 1 to Obj.ElementCount do
        if not (Obj.Elements[i] is TAlgosimNumber) then
          ErrInvalidArguments;
      Result := TAlgosimArray.CreateUninitialized(Max(0, Obj.ElementCount - 1));
      for var i := 2 to Obj.ElementCount do
        Result.Elements[i - 1] := TAlgosimNumber.Subtract(TAlgosimNumber(Obj.Elements[i]), TAlgosimNumber(Obj.Elements[Pred(i)]));
    end;
  end
  else if Obj is TAlgosimVector then
    Result := TAlgosimVector(Obj).Deltas
  else
    ErrInvalidArguments;

end;

{ FCN_MovingAverage }

procedure FCN_MovingAverage.SimpleFunction;
begin

  var Obj := TAlgosimObject(nil);
  var n := 0;
  var LWeights := Default(TRealVector);
  if Args.PeekAt(1) is TAlgosimVector then
    Args.Extract(Obj).Extract(LWeights).Close
  else
    Args.Extract(Obj).ExtractPos(n, 9).Close;

  if Obj is TAlgosimVector then
    Result := TAlgosimVector(Obj).MovingAverage(n, LWeights.Data)
  else if Obj is TAlgosimMatrix then
    Result := TAlgosimMatrix(Obj).MovingAverage(n, LWeights.Data)
  else if Obj is TAlgosimArray then
    Result := TAlgosimArray(Obj).MovingAverage(n, LWeights.Data)
  else
    ErrInvalidArguments;

end;

{ FCN_Settings }

procedure FCN_Settings.SimpleFunction;
begin
  Args.Close;
  var L := TList<string>.Create;
  try
    if Context.Perform(CLIENT_COMMAND_ENUMSETTINGS, NativeInt(L)) then
      Result := TAlgosimArray.CreateWithValue(L.ToArray)
    else
      ErrInternal;
  finally
    L.Free;
  end;
end;

{ FCN_Setting }

procedure FCN_Setting.SimpleFunction;
begin
  var S: string;
  Args.Extract(S).Close;
  var LSetting := Default(TSetting);
  LSetting.Name := S;
  if Context.Perform(CLIENT_COMMAND_QUERYSETTING, NativeInt(@LSetting)) then
    Result := ASOSetting(LSetting.Name, LSetting.&Type.ToLocalizedString,
      LSetting.DefaultValueObject, LSetting.ValueObject, LSetting.Description)
  else
    raise ERuntimeException.CreateFmt('Unable to query setting "%s".', [S])
end;

{ FCN_ApplySetting }

procedure FCN_ApplySetting.SimpleFunction;
begin
  var S: string;
  var V: TAlgosimObject;
  Args.Extract(S).Extract(V).Close;
  var LSetting := Default(TSetting);
  LSetting.Name := S;
  if Context.Perform(CLIENT_COMMAND_QUERYSETTING, NativeInt(@LSetting)) then
  begin
    var LRes := False;
    case LSetting.&Type of
      sdtBoolean:
        LRes := Context.Perform(CLIENT_COMMAND_APPLYSETTING, NativeInt(PChar(S)), Ord(LSetting.&Type), Ord(V.ToBoolean));
      sdtInteger:
        LRes := Context.Perform(CLIENT_COMMAND_APPLYSETTING, NativeInt(PChar(S)), Ord(LSetting.&Type), Ord(V.ToInteger));
      sdtColor:
        LRes := Context.Perform(CLIENT_COMMAND_APPLYSETTING, NativeInt(PChar(S)), Ord(LSetting.&Type), TColor(V.ToColor));
      sdtDouble:
        begin
          var d: Double := V.ToASR;
          LRes := Context.Perform(CLIENT_COMMAND_APPLYSETTING, NativeInt(PChar(S)), Ord(LSetting.&Type), NativeUInt(@d));
        end;
      sdtString:
        LRes := Context.Perform(CLIENT_COMMAND_APPLYSETTING, NativeInt(PChar(S)), Ord(LSetting.&Type), NativeInt(PChar(V.ToString)));
      sdtDateTime:
        begin
          var dt := ASOToDateTime(V);
          LRes := Context.Perform(CLIENT_COMMAND_APPLYSETTING, NativeInt(PChar(S)), Ord(LSetting.&Type), NativeUInt(@dt));
        end;
    end;
    Result := TAlgosimSuccessIndication.CreateWithValue(LRes);
  end
  else
    raise ERuntimeException.CreateFmt('Unable to query setting "%s".', [S])
end;

{ FCN_ContourPlot }

procedure FCN_ContourPlot.SimpleFunction;
var
  F: TAlgosimFunctionObject;
  vx, vy: TRealVector;
  x0, x1, xd, Dx,
  y0, y1, yd, Dy: TASR;
  xn, yn: Cardinal;
  opts: TSysCharSet;
  lvlobj: TAlgosimObject;
begin

  Args
    .Extract(F)
    .Extract(vx)
    .Extract(vy)
    .Extract(lvlobj, nil)
    .Extract(opts, restr, ['i', 's'], defval, ['i', 's'])
    .Close;

  var LevelCount := 0;
  var Levels := TArray<TASR>(nil);
  if lvlobj = nil then
    LevelCount := 12
  else if lvlobj is TAlgosimNumber then
  begin
    LevelCount := lvlobj.ToASI;
    if LevelCount < 1 then
      ErrInvalidArguments;
  end
  else if lvlobj is TAlgosimVector then
  begin
    Levels := lvlobj.ToRealVector.Data;
    if Length(Levels) = 0 then
      ErrInvalidArguments;
  end
  else
    ErrInvalidArguments;

  if vx.Dimension in [2, 3] then
  begin
    x0 := vx[0];
    x1 := vx[1];
    Dx := x1 - x0;
    if vx.Dimension = 3 then
      xd := vx[2]
    else
      xd := 0;
  end
  else
    ErrInvalidArguments;
  if vy.Dimension in [2, 3] then
  begin
    y0 := vy[0];
    y1 := vy[1];
    Dy := y1 - y0;
    if vy.Dimension = 3 then
      yd := vy[2]
    else
      yd := 0;
  end
  else
    ErrInvalidArguments;

  if (Dx <= 0) or (Dy <= 0) then
    ErrInvalidArguments;

  const SampleCount = Sqr(TNumericSettingsCache.Numerics_ContourSamplesPerAxis);
  const Aspect = Dx / Dy;

  if xd > 0 then
    xn := Round(Dx / xd) + 1
  else
    xn := Ceil(Sqrt(SampleCount / Aspect));

  if yd > 0 then
    yn := Round(Dy / yd) + 1
  else
    yn := Ceil(Sqrt(SampleCount * Aspect));

  if xn < 1 then xn := 1;
  if yn < 1 then yn := 1;

  if (xn > 1E8) or (yn > 1E8) or (xn * yn > 1E8) then
    raise EInvArgs.Create('Too great resolution.');

  xd := (x1 - x0) / (xn - 1);
  yd := (y1 - y0) / (yn - 1);

  var A := TRealMatrix.CreateUninitialized(
    TMatrixSize.Create(yn, xn)
  );
  for var iy := 0 to yn - 1 do
    for var ix := 0 to xn - 1 do
    begin
      var x := x0 + ix * xd;
      var y := y1 - iy * yd;
      var z: TASR;
      var Obj := F.Execute(Context, [ASO(x), ASO(y)], True);
      try
        z := Obj.ToASR;
      finally
        Obj.Free;
      end;
      A[iy, ix] := z;
    end;

  var LSampleMeta := Default(TSampleMeta);
  LSampleMeta.xmin := x0;
  LSampleMeta.xmax := x1;
  LSampleMeta.ymin := y0;
  LSampleMeta.ymax := y1;
  LSampleMeta.nx := xn;
  LSampleMeta.ny := yn;

  var LContourOptions := Default(TContourMeta);
  LContourOptions.Automatic   := LevelCount <> 0;
  LContourOptions.Count       := LevelCount;
  LContourOptions.Levels      := Levels;
  LContourOptions.Interpolate := AnsiChar('i') in opts;
  LContourOptions.Simplify    := AnsiChar('s') in opts;

  var LContour := ASContours.Contours(LSampleMeta, A.Data, LContourOptions);


  var RX, RY: TDataRange;
  var ScatterData := GetScatterDataR2(LContour, @RX, @RY);
  FVisual := TVisual.Create2D(vkXYPlot, ScatterData,
    procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
    var
      A, B: Double;
    begin
      A := RY.Min - 0.1*RY.Span;
      B := RY.Max + 0.1*RY.Span;
      ACtl.View.&Set(RX.Min - 0.1*RX.Span, RX.Max + 0.1*RX.Span, A, B, True);
    end,
    procedure(ACtl: TVisCtl2D; ADrawable: TDrawable)
    begin
      with ADrawable as TXYPlot do
      begin
        Points := False;
        Lines := True;
      end;
    end
  );

  if LContourOptions.Simplify then
  begin
    var LCircles := TDictionary<Integer, TCircleRec>.Create;
    try
      ASContours.CircleDetect(LSampleMeta, LContour, LCircles);
    except
      LCircles.Free;
      raise;
    end;
    ScatterData.Metadata := LCircles;
  end;

  inherited;

end;

{ FCN_Panels }

procedure FCN_Panels.SimpleFunction;
begin

  Args.Close;
  var L := TList<TPanelRec>.Create;
  try
    if Context.Perform(CLIENT_COMMAND_ENUMPANELS, NativeInt(L)) then
    begin
      Result := TAlgosimArray.CreateUninitialized(L.Count);
      for var i := 0 to L.Count - 1 do
        Result.Elements[i + 1] := ASOPanel(L[i].ID, L[i].Name, L[i].&Type);
    end
    else
      ErrInternal;
  finally
    L.Free;
  end;

end;

{ FCN_ClosePanel }

procedure FCN_ClosePanel.SimpleFunction;
begin

  var pn := TAlgosimTypedStructure(nil);
  var id := '';
  var guid: TGUID;

  if Args.PeekAt(0) is TAlgosimTypedStructure then
  begin
    Args.Extract(pn, stPanel).Close;
    guid := TGUID.Create(pn['ID'].ToString);
  end
  else
  begin
    Args.Extract(id).Close;
    guid := TGUID.Create(id);
  end;

  if not Context.Perform(CLIENT_COMMAND_CLOSEPANEL, NativeInt(@guid)) then
    ErrInternal;

end;

{ FCN_DebugLog }

procedure FCN_DebugLog.SimpleFunction;
begin

  if Args.Count = 0 then
  begin
    Args.Close;
    var L := TList<string>.Create;
    try
      if Context.Perform(CLIENT_COMMAND_GETLOG, NativeInt(L)) then
      begin
        Result := TAlgosimArray.CreateUninitialized(L.Count);
        for var i := 0 to L.Count - 1 do
          Result.Elements[i + 1] := ASO(L[i]);
      end
      else
        ErrInternal;
    finally
      L.Free;
    end;
  end
  else
  begin
    var S: string;
    Args.Extract(S).Close;
    Context.Perform(CLIENT_COMMAND_DEBUGTEXT, NativeInt(PChar(s)));
    Result := ASO(S);
  end;

end;

{ FCN_ApplyLayout }

procedure FCN_ApplyLayout.SimpleFunction;
begin
  var L := '';
  Args.Extract(L).Close;
  Result := TAlgosimSuccessIndication.CreateWithValue(
    Context.Perform(CLIENT_COMMAND_APPLYLAYOUT, NativeInt(PChar(L)))
  );
end;

end.
