2014-06-27 14:24:23 +00:00
|
|
|
unit fpsmath;
|
|
|
|
|
|
|
|
{$mode objfpc}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
|
|
|
Classes, SysUtils, fpspreadsheet;
|
|
|
|
|
|
|
|
type
|
2014-06-30 10:39:49 +00:00
|
|
|
TsArgumentType = (atNumber, atString, atBool, atError, atEmpty);
|
2014-06-27 14:24:23 +00:00
|
|
|
|
|
|
|
TsArgument = record
|
|
|
|
IsMissing: Boolean;
|
|
|
|
case ArgumentType: TsArgumentType of
|
|
|
|
atNumber : (NumberValue: Double);
|
|
|
|
atString : (StringValue: String);
|
|
|
|
atBool : (BoolValue: Boolean);
|
2014-06-28 19:40:28 +00:00
|
|
|
atError : (ErrorValue: TsErrorValue);
|
2014-06-27 14:24:23 +00:00
|
|
|
end;
|
|
|
|
PsArgument = ^TsArgument;
|
|
|
|
|
|
|
|
TsArgumentStack = class(TFPList)
|
|
|
|
public
|
|
|
|
destructor Destroy; override;
|
|
|
|
function Pop: TsArgument;
|
|
|
|
procedure Push(AValue: TsArgument);
|
|
|
|
procedure PushBool(AValue: Boolean);
|
|
|
|
procedure PushMissing;
|
|
|
|
procedure PushNumber(AValue: Double);
|
|
|
|
procedure PushString(AValue: String);
|
|
|
|
procedure Clear;
|
|
|
|
procedure Delete(AIndex: Integer);
|
|
|
|
end;
|
|
|
|
|
2014-06-28 19:40:28 +00:00
|
|
|
procedure FixMissingBool (var Arg: TsArgument; ABool: Boolean);
|
|
|
|
procedure FixMissingNumber(var Arg: TsArgument; ANumber: Double);
|
|
|
|
procedure FixMissingString(var Arg: TsArgument; AString: String);
|
2014-06-27 14:24:23 +00:00
|
|
|
|
2014-06-28 19:40:28 +00:00
|
|
|
function CreateBool(AValue: Boolean): TsArgument;
|
|
|
|
function CreateNumber(AValue: Double): TsArgument;
|
|
|
|
function CreateString(AValue: String): TsArgument;
|
|
|
|
function CreateError(AError: TsErrorValue): TsArgument;
|
2014-06-30 10:39:49 +00:00
|
|
|
function CreateEmpty: TsArgument;
|
2014-06-28 19:40:28 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
These are the functions called when calculating an RPN formula.
|
|
|
|
}
|
2014-06-27 14:24:23 +00:00
|
|
|
type
|
2014-06-30 08:41:29 +00:00
|
|
|
TsFormulaFunc = function(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
|
|
|
|
function fpsAdd (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsSub (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsMul (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsDiv (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsPercent (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsPower (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsUMinus (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsUPlus (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsConcat (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsEqual (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsGreater (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsGreaterEqual(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsLess (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsLessEqual (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsNotEqual (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-30 13:21:04 +00:00
|
|
|
{ Math }
|
|
|
|
function fpsABS (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsACOS (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsACOSH (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsASIN (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsASINH (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsATAN (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsATANH (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsCOS (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsCOSH (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsDEGREES (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsEXP (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsINT (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsLN (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsLOG (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsLOG10 (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsPI (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsRADIANS (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsRAND (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsROUND (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsSIGN (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsSIN (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsSINH (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsSQRT (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsTAN (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsTANH (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
{ Logic }
|
2014-06-30 10:39:49 +00:00
|
|
|
function fpsAND (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsFALSE (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsIF (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsNOT (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsOR (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
function fpsTRUE (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-27 14:24:23 +00:00
|
|
|
|
|
|
|
implementation
|
|
|
|
|
2014-06-28 19:40:28 +00:00
|
|
|
uses
|
|
|
|
Math;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
type
|
|
|
|
TBoolArray = array of boolean;
|
|
|
|
TFloatArray = array of double;
|
|
|
|
TStrArray = array of string;
|
2014-06-27 14:24:23 +00:00
|
|
|
|
|
|
|
{ TsArgumentStack }
|
|
|
|
|
|
|
|
destructor TsArgumentStack.Destroy;
|
|
|
|
begin
|
|
|
|
Clear;
|
|
|
|
inherited Destroy;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsArgumentStack.Clear;
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
begin
|
|
|
|
for i := Count-1 downto 0 do
|
|
|
|
Delete(i);
|
|
|
|
inherited Clear;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsArgumentStack.Delete(AIndex: Integer);
|
|
|
|
var
|
|
|
|
P: PsArgument;
|
|
|
|
begin
|
|
|
|
P := PsArgument(Items[AIndex]);
|
|
|
|
P^.StringValue := '';
|
|
|
|
FreeMem(P, SizeOf(P));
|
|
|
|
inherited Delete(AIndex);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TsArgumentStack.Pop: TsArgument;
|
|
|
|
var
|
|
|
|
P: PsArgument;
|
|
|
|
begin
|
|
|
|
P := PsArgument(Items[Count-1]);
|
|
|
|
Result := P^;
|
|
|
|
Result.StringValue := P^.StringValue; // necessary?
|
|
|
|
Delete(Count-1);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsArgumentStack.Push(AValue: TsArgument);
|
|
|
|
var
|
|
|
|
P: PsArgument;
|
|
|
|
begin
|
|
|
|
GetMem(P, SizeOf(TsArgument));
|
|
|
|
P^ := AValue;
|
|
|
|
P^.StringValue := AValue.StringValue;
|
|
|
|
Add(P);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsArgumentStack.PushBool(AValue: Boolean);
|
|
|
|
var
|
|
|
|
arg: TsArgument;
|
|
|
|
begin
|
|
|
|
arg.ArgumentType := atBool;
|
|
|
|
arg.BoolValue := AValue;
|
|
|
|
arg.IsMissing := false;
|
|
|
|
Push(arg);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsArgumentStack.PushMissing;
|
|
|
|
var
|
|
|
|
arg: TsArgument;
|
|
|
|
begin
|
|
|
|
arg.IsMissing := true;
|
|
|
|
Push(arg);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsArgumentStack.PushNumber(AValue: Double);
|
|
|
|
var
|
|
|
|
arg: TsArgument;
|
|
|
|
begin
|
|
|
|
arg.ArgumentType := atNumber;
|
|
|
|
arg.NumberValue := AValue;
|
|
|
|
arg.IsMissing := false;
|
|
|
|
Push(arg);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TsArgumentStack.PushString(AValue: String);
|
|
|
|
var
|
|
|
|
arg: TsArgument;
|
|
|
|
begin
|
|
|
|
arg.ArgumentType := atString;
|
|
|
|
arg.StringValue := AValue;
|
|
|
|
arg.IsMissing := false;
|
|
|
|
Push(arg);
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Missing arguments }
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Replaces a missing boolean argument by the passed boolean value
|
|
|
|
@param Arg Argument to be considered
|
|
|
|
@param ABool Replacement for the missing value
|
|
|
|
}
|
2014-06-28 19:40:28 +00:00
|
|
|
procedure FixMissingBool(var Arg: TsArgument; ABool: Boolean);
|
2014-06-27 14:24:23 +00:00
|
|
|
begin
|
|
|
|
if Arg.IsMissing then Arg.BoolValue := ABool;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Replaces a missing number argument by the passed number value
|
|
|
|
@param Arg Argument to be considered
|
|
|
|
@param ANumber Replacement for the missing value
|
|
|
|
}
|
2014-06-28 19:40:28 +00:00
|
|
|
procedure FixMissingNumber(var Arg: TsArgument; ANumber: Double);
|
2014-06-27 14:24:23 +00:00
|
|
|
begin
|
|
|
|
if Arg.IsMissing then Arg.NumberValue := ANumber;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{@@
|
|
|
|
Replaces a missing string argument by the passed string value
|
|
|
|
@param Arg Argument to be considered
|
|
|
|
@param AString Replacement for the missing value
|
|
|
|
}
|
2014-06-28 19:40:28 +00:00
|
|
|
procedure FixMissingString(var Arg: TsArgument; AString: String);
|
2014-06-27 14:24:23 +00:00
|
|
|
begin
|
|
|
|
if Arg.IsMissing then Arg.StringValue := AString;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Preparing arguments }
|
|
|
|
|
2014-06-28 19:40:28 +00:00
|
|
|
function GetBoolFromArgument(Arg: TsArgument; var AValue: Boolean): TsErrorValue;
|
|
|
|
begin
|
|
|
|
case Arg.ArgumentType of
|
|
|
|
atBool : begin
|
|
|
|
AValue := Arg.BoolValue;
|
|
|
|
Result := errOK;
|
|
|
|
end;
|
|
|
|
else Result := errWrongType;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function GetNumberFromArgument(Arg: TsArgument; var ANumber: Double): TsErrorValue;
|
2014-06-27 14:24:23 +00:00
|
|
|
begin
|
2014-06-28 19:40:28 +00:00
|
|
|
Result := errOK;
|
2014-06-27 14:24:23 +00:00
|
|
|
case Arg.ArgumentType of
|
|
|
|
atNumber : ANumber := Arg.NumberValue;
|
2014-06-28 19:40:28 +00:00
|
|
|
atString : if not TryStrToFloat(arg.StringValue, ANumber) then Result := errWrongType;
|
2014-06-27 14:24:23 +00:00
|
|
|
atBool : if Arg.BoolValue then ANumber := 1.0 else ANumber := 0.0;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-06-28 19:40:28 +00:00
|
|
|
function GetStringFromArgument(Arg: TsArgument; var AString: String): TsErrorValue;
|
|
|
|
begin
|
|
|
|
case Arg.ArgumentType of
|
|
|
|
atString : begin
|
|
|
|
AString := Arg.StringValue;
|
|
|
|
Result := errOK;
|
|
|
|
end;
|
|
|
|
else Result := errWrongType;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function CreateBool(AValue: Boolean): TsArgument;
|
|
|
|
begin
|
|
|
|
Result.ArgumentType := atBool;
|
|
|
|
Result.Boolvalue := AValue;
|
|
|
|
end;
|
|
|
|
|
2014-06-27 14:24:23 +00:00
|
|
|
function CreateNumber(AValue: Double): TsArgument;
|
|
|
|
begin
|
|
|
|
Result.ArgumentType := atNumber;
|
|
|
|
Result.NumberValue := AValue;
|
|
|
|
end;
|
|
|
|
|
2014-06-28 19:40:28 +00:00
|
|
|
function CreateString(AValue: String): TsArgument;
|
|
|
|
begin
|
|
|
|
Result.ArgumentType := atString;
|
|
|
|
Result.StringValue := AValue;
|
|
|
|
end;
|
2014-06-27 14:24:23 +00:00
|
|
|
|
2014-06-28 19:40:28 +00:00
|
|
|
function CreateError(AError: TsErrorValue): TsArgument;
|
2014-06-27 14:24:23 +00:00
|
|
|
begin
|
|
|
|
Result.ArgumentType := atError;
|
|
|
|
Result.ErrorValue := AError;
|
|
|
|
end;
|
|
|
|
|
2014-06-30 10:39:49 +00:00
|
|
|
function CreateEmpty: TsArgument;
|
2014-06-28 19:40:28 +00:00
|
|
|
begin
|
2014-06-30 10:39:49 +00:00
|
|
|
Result.ArgumentType := atEmpty;
|
2014-06-28 19:40:28 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
{@@
|
|
|
|
Pops boolean values from the argument stack. Is called when calculating rpn
|
|
|
|
formulas.
|
|
|
|
@param Args Argument stack to be used.
|
|
|
|
@param NumArgs Count of arguments to be popped from the stack
|
|
|
|
@param AValues (output) Array containing the retrieved boolean values.
|
|
|
|
The array length is given by NumArgs. The data in the array
|
|
|
|
are in the same order in which they were pushed onto the stack.
|
|
|
|
@param AErrArg (output) Argument containing an error code, e.g. errWrongType
|
|
|
|
if non-boolean data were met on the stack.
|
|
|
|
@return TRUE if everything was ok, FALSE, if AErrArg reports an error. }
|
|
|
|
function PopBoolValues(Args: TsArgumentStack; NumArgs: Integer;
|
|
|
|
out AValues: TBoolArray; out AErrArg: TsArgument): Boolean;
|
2014-06-27 14:24:23 +00:00
|
|
|
var
|
2014-06-28 19:40:28 +00:00
|
|
|
err: TsErrorValue;
|
2014-06-30 08:41:29 +00:00
|
|
|
i: Integer;
|
2014-06-27 14:24:23 +00:00
|
|
|
begin
|
2014-06-30 08:41:29 +00:00
|
|
|
SetLength(AValues, NumArgs);
|
|
|
|
// Pop the data in reverse order they were pushed! Otherwise they will be
|
|
|
|
// applied to the function in the wrong order.
|
|
|
|
for i := NumArgs-1 downto 0 do begin
|
|
|
|
err := GetBoolFromArgument(Args.Pop, AValues[i]);
|
|
|
|
if err <> errOK then begin
|
|
|
|
Result := false;
|
|
|
|
AErrArg := CreateError(err);
|
|
|
|
SetLength(AValues, 0);
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
Result := true;
|
|
|
|
AErrArg := CreateError(errOK);
|
2014-06-27 14:24:23 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
{@@
|
|
|
|
Pops floating point values from the argument stack. Is called when
|
|
|
|
calculating rpn formulas.
|
|
|
|
@param Args Argument stack to be used.
|
|
|
|
@param NumArgs Count of arguments to be popped from the stack
|
|
|
|
@param AValues (output) Array containing the retrieved float values.
|
|
|
|
The array length is given by NumArgs. The data in the array
|
|
|
|
are in the same order in which they were pushed onto the stack.
|
|
|
|
@param AErrArg (output) Argument containing an error code, e.g. errWrongType
|
|
|
|
if non-float data were met on the stack.
|
|
|
|
@return TRUE if everything was ok, FALSE, if AErrArg reports an error. }
|
|
|
|
function PopFloatValues(Args: TsArgumentStack; NumArgs: Integer;
|
|
|
|
out AValues: TFloatArray; out AErrArg: TsArgument): Boolean;
|
2014-06-27 14:24:23 +00:00
|
|
|
var
|
2014-06-28 19:40:28 +00:00
|
|
|
err: TsErrorValue;
|
2014-06-30 08:41:29 +00:00
|
|
|
i: Integer;
|
2014-06-27 14:24:23 +00:00
|
|
|
begin
|
2014-06-30 08:41:29 +00:00
|
|
|
SetLength(AValues, NumArgs);
|
|
|
|
// Pop the data in reverse order they were pushed! Otherwise they will be
|
|
|
|
// applied to the function in the wrong order.
|
|
|
|
for i := NumArgs-1 downto 0 do begin
|
|
|
|
err := GetNumberFromArgument(Args.Pop, AValues[i]);
|
|
|
|
if err <> errOK then begin
|
|
|
|
Result := false;
|
|
|
|
SetLength(AValues, 0);
|
|
|
|
AErrArg := CreateError(errWrongType);
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
Result := true;
|
|
|
|
AErrArg := CreateError(errOK);
|
2014-06-27 14:24:23 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
{@@
|
|
|
|
Pops string arguments from the argument stack. Is called when calculating
|
|
|
|
rpn formulas.
|
|
|
|
@param Args Argument stack to be used.
|
|
|
|
@param NumArgs Count of arguments to be popped from the stack
|
|
|
|
@param AValues (output) Array containing the retrieved strings. The array
|
|
|
|
length is given by NumArgs. The data in the array are in the
|
|
|
|
same order in which they were pushed onto the stack.
|
|
|
|
@param AErrArg (output) Argument containing an error code , e.g. errWrongType
|
|
|
|
if non-string data were met on the stack.
|
|
|
|
@return TRUE if everything was ok, FALSE, if AErrArg reports an error. }
|
|
|
|
function PopStringValues(Args: TsArgumentStack; NumArgs: Integer;
|
|
|
|
out AValues: TStrArray; out AErrArg: TsArgument): Boolean;
|
2014-06-27 14:24:23 +00:00
|
|
|
var
|
2014-06-28 19:40:28 +00:00
|
|
|
err: TsErrorValue;
|
2014-06-30 08:41:29 +00:00
|
|
|
i: Integer;
|
2014-06-27 14:24:23 +00:00
|
|
|
begin
|
2014-06-30 08:41:29 +00:00
|
|
|
SetLength(AValues, NumArgs);
|
|
|
|
// Pop the data in reverse order they were pushed! Otherwise they will be
|
|
|
|
// applied to the function in the wrong order.
|
|
|
|
for i := NumArgs-1 downto 0 do begin
|
|
|
|
err := GetStringFromArgument(Args.Pop, AValues[i]);
|
|
|
|
if err <> errOK then begin
|
|
|
|
Result := false;
|
|
|
|
AErrArg := CreateError(errWrongType);
|
|
|
|
SetLength(AValues, 0);
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
Result :=true;
|
|
|
|
AErrArg := CreateError(errOK);
|
2014-06-27 14:24:23 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
|
|
|
|
{ Operations }
|
|
|
|
|
|
|
|
function fpsAdd(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-27 14:24:23 +00:00
|
|
|
var
|
2014-06-30 08:41:29 +00:00
|
|
|
data: TFloatArray;
|
2014-06-27 14:24:23 +00:00
|
|
|
begin
|
2014-06-30 08:41:29 +00:00
|
|
|
if PopFloatValues(Args, 2, data, Result) then
|
|
|
|
Result := CreateNumber(data[0] + data[1]);
|
2014-06-27 14:24:23 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
function fpsSub(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-28 19:40:28 +00:00
|
|
|
var
|
2014-06-30 08:41:29 +00:00
|
|
|
data: TFloatArray;
|
2014-06-28 19:40:28 +00:00
|
|
|
begin
|
2014-06-30 08:41:29 +00:00
|
|
|
if PopFloatValues(Args, 2, data, Result) then
|
|
|
|
Result := CreateNumber(data[0] - data[1]);
|
2014-06-28 19:40:28 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
function fpsMul(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-28 19:40:28 +00:00
|
|
|
var
|
2014-06-30 08:41:29 +00:00
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 2, data, Result) then
|
|
|
|
Result := CreateNumber(data[0] * data[1]);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsDiv(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 2, data, Result) then begin
|
|
|
|
if data[1] = 0 then
|
|
|
|
Result := CreateError(errDivideByZero)
|
|
|
|
else
|
|
|
|
Result := CreateNumber(data[0] / data[1]);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsPercent(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(data[0] * 0.01);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsPower(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
2014-06-28 19:40:28 +00:00
|
|
|
begin
|
2014-06-30 08:41:29 +00:00
|
|
|
if PopFloatValues(Args, 2, data, Result) then
|
2014-06-28 19:40:28 +00:00
|
|
|
try
|
2014-06-30 08:41:29 +00:00
|
|
|
Result := CreateNumber(power(data[0], data[1]));
|
2014-06-28 19:40:28 +00:00
|
|
|
except on E: EInvalidArgument do
|
|
|
|
Result := CreateError(errOverflow);
|
|
|
|
// this could happen, e.g., for "power( (neg value), (non-integer) )"
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
function fpsUMinus(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-28 19:40:28 +00:00
|
|
|
var
|
2014-06-30 08:41:29 +00:00
|
|
|
data: TFloatArray;
|
2014-06-28 19:40:28 +00:00
|
|
|
begin
|
2014-06-30 08:41:29 +00:00
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(-data[0]);
|
2014-06-28 19:40:28 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
function fpsUPlus(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-28 19:40:28 +00:00
|
|
|
var
|
2014-06-30 08:41:29 +00:00
|
|
|
data: TFloatArray;
|
2014-06-28 19:40:28 +00:00
|
|
|
begin
|
2014-06-30 08:41:29 +00:00
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(data[0]);
|
2014-06-28 19:40:28 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
function fpsConcat(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-28 19:40:28 +00:00
|
|
|
var
|
2014-06-30 08:41:29 +00:00
|
|
|
data: TStrArray;
|
2014-06-28 19:40:28 +00:00
|
|
|
begin
|
2014-06-30 08:41:29 +00:00
|
|
|
if PopStringValues(Args, 2, data, Result) then
|
|
|
|
Result := CreateString(data[0] + data[1]);
|
2014-06-28 19:40:28 +00:00
|
|
|
end;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
function fpsEqual(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-29 09:55:47 +00:00
|
|
|
var
|
|
|
|
arg1, arg2: TsArgument;
|
|
|
|
begin
|
|
|
|
arg2 := Args.Pop;
|
|
|
|
arg1 := Args.Pop;
|
|
|
|
if arg1.ArgumentType = arg2.ArgumentType then
|
|
|
|
case arg1.ArgumentType of
|
|
|
|
atNumber : Result := CreateBool(arg1.NumberValue = arg2.NumberValue);
|
|
|
|
atString : Result := CreateBool(arg1.StringValue = arg2.StringValue);
|
|
|
|
atBool : Result := CreateBool(arg1.Boolvalue = arg2.BoolValue);
|
|
|
|
end
|
|
|
|
else
|
|
|
|
Result := CreateBool(false);
|
|
|
|
end;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
function fpsGreater(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-29 09:55:47 +00:00
|
|
|
var
|
|
|
|
arg1, arg2: TsArgument;
|
|
|
|
begin
|
|
|
|
arg2 := Args.Pop;
|
|
|
|
arg1 := Args.Pop;
|
|
|
|
if arg1.ArgumentType = arg2.ArgumentType then
|
|
|
|
case arg1.ArgumentType of
|
|
|
|
atNumber : Result := CreateBool(arg1.NumberValue > arg2.NumberValue);
|
|
|
|
atString : Result := CreateBool(arg1.StringValue > arg2.StringValue);
|
|
|
|
atBool : Result := CreateBool(arg1.Boolvalue > arg2.BoolValue);
|
|
|
|
end
|
|
|
|
else
|
|
|
|
Result := CreateBool(false);
|
|
|
|
end;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
function fpsGreaterEqual(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-29 09:55:47 +00:00
|
|
|
var
|
|
|
|
arg1, arg2: TsArgument;
|
|
|
|
begin
|
|
|
|
arg2 := Args.Pop;
|
|
|
|
arg1 := Args.Pop;
|
|
|
|
if arg1.ArgumentType = arg2.ArgumentType then
|
|
|
|
case arg1.ArgumentType of
|
|
|
|
atNumber : Result := CreateBool(arg1.NumberValue >= arg2.NumberValue);
|
|
|
|
atString : Result := CreateBool(arg1.StringValue >= arg2.StringValue);
|
|
|
|
atBool : Result := CreateBool(arg1.Boolvalue >= arg2.BoolValue);
|
|
|
|
end
|
|
|
|
else
|
|
|
|
Result := CreateBool(false);
|
|
|
|
end;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
function fpsLess(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-29 09:55:47 +00:00
|
|
|
var
|
|
|
|
arg1, arg2: TsArgument;
|
|
|
|
begin
|
|
|
|
arg2 := Args.Pop;
|
|
|
|
arg1 := Args.Pop;
|
|
|
|
if arg1.ArgumentType = arg2.ArgumentType then
|
|
|
|
case arg1.ArgumentType of
|
|
|
|
atNumber : Result := CreateBool(arg1.NumberValue < arg2.NumberValue);
|
|
|
|
atString : Result := CreateBool(arg1.StringValue < arg2.StringValue);
|
|
|
|
atBool : Result := CreateBool(arg1.Boolvalue < arg2.BoolValue);
|
|
|
|
end
|
|
|
|
else
|
|
|
|
Result := CreateBool(false);
|
|
|
|
end;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
function fpsLessEqual(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-29 09:55:47 +00:00
|
|
|
var
|
|
|
|
arg1, arg2: TsArgument;
|
|
|
|
begin
|
|
|
|
arg2 := Args.Pop;
|
|
|
|
arg1 := Args.Pop;
|
|
|
|
if arg1.ArgumentType = arg2.ArgumentType then
|
|
|
|
case arg1.ArgumentType of
|
|
|
|
atNumber : Result := CreateBool(arg1.NumberValue <= arg2.NumberValue);
|
|
|
|
atString : Result := CreateBool(arg1.StringValue <= arg2.StringValue);
|
|
|
|
atBool : Result := CreateBool(arg1.Boolvalue <= arg2.BoolValue);
|
|
|
|
end
|
|
|
|
else
|
|
|
|
Result := CreateBool(false);
|
|
|
|
end;
|
|
|
|
|
2014-06-30 08:41:29 +00:00
|
|
|
function fpsNotEqual(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-29 09:55:47 +00:00
|
|
|
var
|
|
|
|
arg1, arg2: TsArgument;
|
|
|
|
begin
|
|
|
|
arg2 := Args.Pop;
|
|
|
|
arg1 := Args.Pop;
|
|
|
|
if arg1.ArgumentType = arg2.ArgumentType then
|
|
|
|
case arg1.ArgumentType of
|
|
|
|
atNumber : Result := CreateBool(arg1.NumberValue <> arg2.NumberValue);
|
|
|
|
atString : Result := CreateBool(arg1.StringValue <> arg2.StringValue);
|
|
|
|
atBool : Result := CreateBool(arg1.Boolvalue <> arg2.BoolValue);
|
|
|
|
end
|
|
|
|
else
|
|
|
|
Result := CreateBool(false);
|
|
|
|
end;
|
|
|
|
|
2014-06-30 13:21:04 +00:00
|
|
|
|
|
|
|
{ Math functions }
|
|
|
|
|
|
|
|
function fpsABS(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(abs(data[0]));
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsACOS(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then begin
|
|
|
|
if InRange(data[0], -1, +1) then
|
|
|
|
Result := CreateNumber(arccos(data[0]))
|
|
|
|
else
|
|
|
|
Result := CreateError(errOverflow); // #NUM!
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsACOSH(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then begin
|
|
|
|
if data[0] >= 1 then
|
|
|
|
Result := CreateNumber(arccosh(data[0]))
|
|
|
|
else
|
|
|
|
Result := CreateError(errOverflow); // #NUM!
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsASIN(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then begin
|
|
|
|
if InRange(data[0], -1, +1) then
|
|
|
|
Result := CreateNumber(arcsin(data[0]))
|
|
|
|
else
|
|
|
|
Result := CreateError(errOverflow); // #NUM!
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsASINH(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(arcsinh(data[0]));
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsATAN(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(arctan(data[0]));
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsATANH(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then begin
|
|
|
|
if (data[0] > -1) and (data[0] < +1) then
|
|
|
|
Result := CreateNumber(arctanh(data[0]))
|
|
|
|
else
|
|
|
|
Result := CreateError(errOverflow); // #NUM!
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsCOS(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(cos(data[0]));
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsCOSH(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(cosh(data[0]));
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsDEGREES(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(RadToDeg(data[0]));
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsEXP(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(exp(data[0]));
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsINT(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(floor(data[0]));
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsLN(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then begin
|
|
|
|
if (data[0] > 0) then
|
|
|
|
Result := CreateNumber(ln(data[0]))
|
|
|
|
else
|
|
|
|
Result := CreateError(errOverflow); // #NUM!
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsLOG(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
arg_base, arg_number: TsArgument;
|
|
|
|
data: TFloatArray;
|
|
|
|
base: Double;
|
|
|
|
begin
|
|
|
|
base := 10;
|
|
|
|
if NumArgs = 2 then begin
|
|
|
|
arg_base := Args.Pop;
|
|
|
|
if not arg_base.IsMissing then begin
|
|
|
|
if arg_base.ArgumentType <> atNumber then begin
|
|
|
|
Result := CreateError(errWrongType);
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
base := arg_base.NumberValue;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if base < 0 then begin
|
|
|
|
Result := CreateError(errOverflow);
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
arg_number := Args.Pop;
|
|
|
|
if arg_number.ArgumentType <> atNumber then begin
|
|
|
|
Result := CreateError(errWrongType);
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
|
|
|
if arg_number.NumberValue > 0 then
|
|
|
|
Result := CreateNumber(logn(base, arg_number.NumberValue))
|
|
|
|
else
|
|
|
|
Result := CreateError(errOverflow);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsLOG10(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then begin
|
|
|
|
if (data[0] > 0) then
|
|
|
|
Result := CreateNumber(log10(data[0]))
|
|
|
|
else
|
|
|
|
Result := CreateError(errOverflow); // #NUM!
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsPI(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
begin
|
|
|
|
Result := CreateNumber(pi);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsRADIANS(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(degtorad(data[0]))
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsRAND(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
begin
|
|
|
|
Result := CreateNumber(random);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsROUND(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 2, data, Result) then
|
|
|
|
Result := CreateNumber(RoundTo(data[0], round(data[1])))
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsSIGN(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(sign(data[0]))
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsSIN(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(sin(data[0]))
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsSINH(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(sinh(data[0]))
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsSQRT(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then begin
|
|
|
|
if data[0] >= 0.0 then
|
|
|
|
Result := CreateNumber(sqrt(data[0]))
|
|
|
|
else
|
|
|
|
Result := CreateError(errOverflow);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsTAN(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then begin
|
|
|
|
if frac(data[0] / (pi*0.5)) = 0 then
|
|
|
|
Result := CreateError(errOverflow)
|
|
|
|
else
|
|
|
|
Result := CreateNumber(tan(data[0]))
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsTANH(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TFloatArray;
|
|
|
|
begin
|
|
|
|
if PopFloatValues(Args, 1, data, Result) then
|
|
|
|
Result := CreateNumber(tanh(data[0]))
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{ Logical functions }
|
|
|
|
|
2014-06-30 10:39:49 +00:00
|
|
|
function fpsAND(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-30 08:41:29 +00:00
|
|
|
var
|
|
|
|
data: TBoolArray;
|
|
|
|
i: Integer;
|
|
|
|
b: Boolean;
|
|
|
|
begin
|
|
|
|
if PopBoolValues(Args, NumArgs, data, Result) then begin
|
|
|
|
// If at least one case is false the entire AND condition is false
|
|
|
|
b := true;
|
|
|
|
for i:=0 to High(data) do
|
|
|
|
if not data[i] then begin
|
|
|
|
b := false;
|
|
|
|
break;
|
|
|
|
end;
|
|
|
|
Result := CreateBool(b);
|
|
|
|
end;
|
|
|
|
end;
|
2014-06-29 09:55:47 +00:00
|
|
|
|
2014-06-30 10:39:49 +00:00
|
|
|
function fpsFALSE(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
begin
|
|
|
|
Result := CreateBool(false);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsIF(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
condition: TsArgument;
|
|
|
|
case1, case2: TsArgument;
|
|
|
|
err: TsErrorValue;
|
|
|
|
begin
|
|
|
|
if NumArgs = 3 then
|
|
|
|
case2 := Args.Pop;
|
|
|
|
case1 := Args.Pop;
|
|
|
|
condition := Args.Pop;
|
|
|
|
if condition.ArgumentType <> atBool then
|
|
|
|
Result := CreateError(errWrongType)
|
|
|
|
else
|
|
|
|
case NumArgs of
|
|
|
|
2: if condition.BoolValue then Result := case1 else Result := Condition;
|
|
|
|
3: if condition.BoolValue then Result := case1 else Result := case2;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsNOT(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
var
|
|
|
|
data: TBoolArray;
|
|
|
|
begin
|
|
|
|
if PopBoolValues(Args, NumArgs, data, Result) then
|
|
|
|
Result := CreateBool(not data[0]);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function fpsOR(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
2014-06-28 19:40:28 +00:00
|
|
|
var
|
2014-06-30 08:41:29 +00:00
|
|
|
data: TBoolArray;
|
|
|
|
i: Integer;
|
|
|
|
b: Boolean;
|
|
|
|
begin
|
|
|
|
if PopBoolValues(Args, NumArgs, data, Result) then begin
|
|
|
|
// If at least one case is true, the entire OR condition is true
|
|
|
|
b := false;
|
|
|
|
for i:=0 to High(data) do
|
|
|
|
if data[i] then begin
|
|
|
|
b := true;
|
|
|
|
break;
|
|
|
|
end;
|
|
|
|
Result := CreateBool(b);
|
|
|
|
end;
|
2014-06-28 19:40:28 +00:00
|
|
|
end;
|
2014-06-27 14:24:23 +00:00
|
|
|
|
2014-06-30 10:39:49 +00:00
|
|
|
function fpsTRUE(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|
|
|
begin
|
|
|
|
Result := CreateBool(true);
|
|
|
|
end;
|
|
|
|
|
2014-06-27 14:24:23 +00:00
|
|
|
end.
|