update to 0.7.0
This commit is contained in:
@@ -1,719 +0,0 @@
|
||||
unit ParseClass;
|
||||
|
||||
interface
|
||||
|
||||
uses OObjects, SysUtils;
|
||||
|
||||
const
|
||||
MaxArg = 6;
|
||||
|
||||
const
|
||||
Nan: Double = 0 / 0;
|
||||
function isNan(const d: Double): boolean;
|
||||
|
||||
type
|
||||
TVarType = (vtDouble, vtBoolean, vtString, vtLeftBracket,
|
||||
vtRightBracket, vtComma);
|
||||
PDouble = ^Double;
|
||||
EParserException = class(Exception);
|
||||
PExpressionRec = ^TExpressionRec;
|
||||
|
||||
TExprWord = class;
|
||||
|
||||
TArgsArray = record
|
||||
Res: Double;
|
||||
Args: array [0 .. MaxArg - 1] of PDouble;
|
||||
ExprWord: TExprWord; // can be used to notify the object to update
|
||||
end;
|
||||
|
||||
TDoubleFunc = procedure(Expr: PExpressionRec);
|
||||
|
||||
TStringFunc = function(s1, s2: string): Double;
|
||||
|
||||
TExpressionRec = record
|
||||
// used both as linked tree and linked list for maximum evaluation efficiency
|
||||
Oper: TDoubleFunc;
|
||||
Next: PExpressionRec;
|
||||
Res: Double;
|
||||
ExprWord: TExprWord;
|
||||
case Byte of
|
||||
0:
|
||||
(Args: array [0 .. MaxArg - 1] of PDouble;
|
||||
// can be used to notify the object to update
|
||||
);
|
||||
1:
|
||||
(ArgList: array [0 .. MaxArg - 1] of PExpressionRec);
|
||||
end;
|
||||
|
||||
TExprCollection = class(TNoOwnerCollection)
|
||||
public
|
||||
function NextOper(IStart: Integer): Integer;
|
||||
procedure Check;
|
||||
procedure EraseExtraBrackets;
|
||||
end;
|
||||
|
||||
TExprWord = class
|
||||
private
|
||||
FName: string;
|
||||
FDoubleFunc: TDoubleFunc;
|
||||
protected
|
||||
function GetIsOper: boolean; virtual;
|
||||
function GetAsString: string; virtual;
|
||||
function GetIsVariable: boolean;
|
||||
function GetCanVary: boolean; virtual;
|
||||
function GetVarType: TVarType; virtual;
|
||||
function GetNFunctionArg: Integer; virtual;
|
||||
function GetDescription: string; virtual;
|
||||
public
|
||||
constructor Create(AName: string; ADoubleFunc: TDoubleFunc);
|
||||
function AsPointer: PDouble; virtual;
|
||||
property AsString: string read GetAsString;
|
||||
property DoubleFunc: TDoubleFunc read FDoubleFunc;
|
||||
property IsOper: boolean read GetIsOper;
|
||||
property CanVary: boolean read GetCanVary;
|
||||
property isVariable: boolean read GetIsVariable;
|
||||
property VarType: TVarType read GetVarType;
|
||||
property NFunctionArg: Integer read GetNFunctionArg;
|
||||
property Name: string read FName;
|
||||
property Description: string read GetDescription;
|
||||
end;
|
||||
|
||||
TExpressList = class(TSortedCollection)
|
||||
public
|
||||
function KeyOf(Item: Pointer): Pointer; override;
|
||||
function Compare(Key1, Key2: Pointer): Integer; override;
|
||||
end;
|
||||
|
||||
TDoubleConstant = class(TExprWord)
|
||||
private
|
||||
FValue: Double;
|
||||
public
|
||||
function AsPointer: PDouble; override;
|
||||
constructor Create(AName: string; AValue: string);
|
||||
constructor CreateAsDouble(AName: string; AValue: Double);
|
||||
// not overloaded to support older Delphi versions
|
||||
property Value: Double read FValue write FValue;
|
||||
end;
|
||||
|
||||
TConstant = class(TDoubleConstant)
|
||||
private
|
||||
FDescription: string;
|
||||
protected
|
||||
function GetDescription: string; override;
|
||||
public
|
||||
constructor CreateAsDouble(AName, Descr: string; AValue: Double);
|
||||
end;
|
||||
|
||||
TBooleanConstant = class(TDoubleConstant)
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
end;
|
||||
|
||||
TGeneratedVariable = class(TDoubleConstant)
|
||||
private
|
||||
FAsString: string;
|
||||
FVarType: TVarType;
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
function GetAsString: string; override;
|
||||
function GetCanVary: boolean; override;
|
||||
public
|
||||
constructor Create(AName: string);
|
||||
property VarType read GetVarType write FVarType;
|
||||
property AsString: string read GetAsString write FAsString;
|
||||
end;
|
||||
|
||||
TDoubleVariable = class(TExprWord)
|
||||
private
|
||||
FValue: PDouble;
|
||||
protected
|
||||
function GetCanVary: boolean; override;
|
||||
public
|
||||
function AsPointer: PDouble; override;
|
||||
constructor Create(AName: string; AValue: PDouble);
|
||||
end;
|
||||
|
||||
TStringConstant = class(TExprWord)
|
||||
private
|
||||
FValue: string;
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
function GetAsString: string; override;
|
||||
public
|
||||
constructor Create(AValue: string);
|
||||
end;
|
||||
|
||||
TLeftBracket = class(TExprWord)
|
||||
function GetVarType: TVarType; override;
|
||||
end;
|
||||
|
||||
TRightBracket = class(TExprWord)
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
end;
|
||||
|
||||
TComma = class(TExprWord)
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
end;
|
||||
|
||||
PString = ^string;
|
||||
|
||||
TStringVariable = class(TExprWord)
|
||||
private
|
||||
FValue: PString;
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
function GetAsString: string; override;
|
||||
function GetCanVary: boolean; override;
|
||||
public
|
||||
constructor Create(AName: string; AValue: PString);
|
||||
end;
|
||||
|
||||
TFunction = class(TExprWord)
|
||||
private
|
||||
FIsOper: boolean;
|
||||
FOperPrec: Integer;
|
||||
FNFunctionArg: Integer;
|
||||
FDescription: string;
|
||||
protected
|
||||
function GetDescription: string; override;
|
||||
function GetIsOper: boolean; override;
|
||||
function GetNFunctionArg: Integer; override;
|
||||
public
|
||||
constructor Create(AName, Descr: string; ADoubleFunc: TDoubleFunc;
|
||||
ANFunctionArg: Integer);
|
||||
constructor CreateOper(AName: string; ADoubleFunc: TDoubleFunc;
|
||||
ANFunctionArg: Integer; AIsOper: boolean; AOperPrec: Integer);
|
||||
property OperPrec: Integer read FOperPrec;
|
||||
end;
|
||||
|
||||
TVaryingFunction = class(TFunction)
|
||||
// Functions that can vary for ex. random generators
|
||||
// should be TVaryingFunction to be sure that they are
|
||||
// always evaluated
|
||||
protected
|
||||
function GetCanVary: boolean; override;
|
||||
end;
|
||||
|
||||
TBooleanFunction = class(TFunction)
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
end;
|
||||
|
||||
TOper = (op_eq, op_gt, op_lt, op_ge, op_le, op_in);
|
||||
|
||||
const
|
||||
ListChar = ','; { the delimiter used with the 'in' operator: e.g.,
|
||||
('a' in 'a,b') =True
|
||||
('c' in 'a,b') =False }
|
||||
|
||||
type
|
||||
TSimpleStringFunction = class(TFunction)
|
||||
private
|
||||
FStringFunc: TStringFunc;
|
||||
FLeftArg: TExprWord;
|
||||
FRightArg: TExprWord;
|
||||
protected
|
||||
function GetCanVary: boolean; override;
|
||||
public
|
||||
constructor Create(AName, Descr: string; AStringFunc: TStringFunc;
|
||||
ALeftArg, ARightArg: TExprWord);
|
||||
function Evaluate: Double;
|
||||
property StringFunc: TStringFunc read FStringFunc;
|
||||
end;
|
||||
|
||||
TVaryingStringFunction = class(TSimpleStringFunction)
|
||||
protected
|
||||
function GetCanVary: boolean; override;
|
||||
end;
|
||||
|
||||
TLogicalStringOper = class(TSimpleStringFunction)
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
public
|
||||
constructor Create(AOper: string; ALeftArg: TExprWord;
|
||||
ARightArg: TExprWord);
|
||||
end;
|
||||
|
||||
procedure _Variable(Param: PExpressionRec);
|
||||
|
||||
// procedure _StringFunc(Param: PExpressionRec);
|
||||
|
||||
implementation
|
||||
|
||||
// function _StrIn(sLookfor, sData: string): Double;
|
||||
|
||||
// function _StrInt(a, b: string): Double;
|
||||
|
||||
function isNan(const d: Double): boolean;
|
||||
begin
|
||||
Result := comp(d) = comp(Nan);
|
||||
// slower alternative: CompareMem(@d, @Nan, SizeOf(Double))
|
||||
end;
|
||||
|
||||
procedure _Variable(Param: PExpressionRec);
|
||||
begin
|
||||
with Param^ do
|
||||
Res := Args[0]^;
|
||||
end;
|
||||
|
||||
procedure _StringFunc(Param: PExpressionRec);
|
||||
begin
|
||||
with Param^ do
|
||||
Res := TSimpleStringFunction(ExprWord).Evaluate;
|
||||
end;
|
||||
|
||||
function _StrInt(a, b: string): Double;
|
||||
begin
|
||||
Result := StrToInt(a);
|
||||
end;
|
||||
|
||||
function _StrEq(s1, s2: string): Double;
|
||||
begin
|
||||
Result := Byte(s1 = s2);
|
||||
end;
|
||||
|
||||
function _StrGt(s1, s2: string): Double;
|
||||
begin
|
||||
Result := Byte(s1 > s2);
|
||||
end;
|
||||
|
||||
function _Strlt(s1, s2: string): Double;
|
||||
begin
|
||||
Result := Byte(s1 < s2);
|
||||
end;
|
||||
|
||||
function _StrGe(s1, s2: string): Double;
|
||||
begin
|
||||
Result := Byte(s1 >= s2);
|
||||
end;
|
||||
|
||||
function _Strle(s1, s2: string): Double;
|
||||
begin
|
||||
Result := Byte(s1 <= s2);
|
||||
end;
|
||||
|
||||
function _Strne(s1, s2: string): Double;
|
||||
begin
|
||||
Result := Byte(s1 <> s2);
|
||||
end;
|
||||
|
||||
function _StrIn(sLookfor, sData: string): Double;
|
||||
var
|
||||
loop: Integer;
|
||||
subString: string;
|
||||
begin
|
||||
Result := 0;
|
||||
loop := pos(ListChar, sData);
|
||||
while loop > 0 do
|
||||
begin
|
||||
subString := Copy(sData, 1, loop - 1);
|
||||
sData := Copy(sData, loop + 1, Length(sData));
|
||||
if subString = sLookfor then
|
||||
begin
|
||||
Result := 1;
|
||||
break;
|
||||
end;
|
||||
loop := pos(ListChar, sData);
|
||||
end;
|
||||
if sLookfor = sData then
|
||||
Result := 1;
|
||||
end;
|
||||
|
||||
{ TExpressionWord }
|
||||
|
||||
function TExprWord.AsPointer: PDouble;
|
||||
begin
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
constructor TExprWord.Create(AName: string; ADoubleFunc: TDoubleFunc);
|
||||
begin
|
||||
FName := LowerCase(AName);
|
||||
FDoubleFunc := ADoubleFunc;
|
||||
end;
|
||||
|
||||
function TExprWord.GetAsString: string;
|
||||
begin
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
function TExprWord.GetCanVary: boolean;
|
||||
begin
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
function TExprWord.GetDescription: string;
|
||||
begin
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
function TExprWord.GetIsOper: boolean;
|
||||
begin
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
function TExprWord.GetIsVariable: boolean;
|
||||
begin
|
||||
Result := @FDoubleFunc = @_Variable
|
||||
end;
|
||||
|
||||
function TExprWord.GetNFunctionArg: Integer;
|
||||
begin
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
function TExprWord.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtDouble;
|
||||
end;
|
||||
|
||||
{ TDoubleConstant }
|
||||
|
||||
function TDoubleConstant.AsPointer: PDouble;
|
||||
begin
|
||||
Result := @FValue;
|
||||
end;
|
||||
|
||||
constructor TDoubleConstant.Create(AName, AValue: string);
|
||||
begin
|
||||
inherited Create(AName, _Variable);
|
||||
if AValue <> '' then
|
||||
FValue := StrToFloat(AValue)
|
||||
else
|
||||
FValue := Nan;
|
||||
end;
|
||||
|
||||
constructor TDoubleConstant.CreateAsDouble(AName: string; AValue: Double);
|
||||
begin
|
||||
inherited Create(AName, _Variable);
|
||||
FValue := AValue;
|
||||
end;
|
||||
|
||||
{ TStringConstant }
|
||||
|
||||
function TStringConstant.GetAsString: string;
|
||||
begin
|
||||
Result := FValue;
|
||||
end;
|
||||
|
||||
constructor TStringConstant.Create(AValue: string);
|
||||
begin
|
||||
inherited Create(AValue, _Variable);
|
||||
if (AValue[1] = '''') and (AValue[Length(AValue)] = '''') then
|
||||
FValue := Copy(AValue, 2, Length(AValue) - 2)
|
||||
else
|
||||
FValue := AValue;
|
||||
end;
|
||||
|
||||
function TStringConstant.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtString;
|
||||
end;
|
||||
|
||||
{ TDoubleVariable }
|
||||
|
||||
function TDoubleVariable.AsPointer: PDouble;
|
||||
begin
|
||||
Result := FValue;
|
||||
end;
|
||||
|
||||
constructor TDoubleVariable.Create(AName: string; AValue: PDouble);
|
||||
begin
|
||||
inherited Create(AName, _Variable);
|
||||
FValue := AValue;
|
||||
end;
|
||||
|
||||
function TDoubleVariable.GetCanVary: boolean;
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
{ TFunction }
|
||||
|
||||
constructor TFunction.Create(AName, Descr: string; ADoubleFunc: TDoubleFunc;
|
||||
ANFunctionArg: Integer);
|
||||
begin
|
||||
FDescription := Descr;
|
||||
CreateOper(AName, ADoubleFunc, ANFunctionArg, False, 0);
|
||||
// to increase compatibility don't use default parameters
|
||||
end;
|
||||
|
||||
constructor TFunction.CreateOper(AName: string; ADoubleFunc: TDoubleFunc;
|
||||
ANFunctionArg: Integer; AIsOper: boolean; AOperPrec: Integer);
|
||||
begin
|
||||
inherited Create(AName, ADoubleFunc);
|
||||
FNFunctionArg := ANFunctionArg;
|
||||
if FNFunctionArg > MaxArg then
|
||||
raise EParserException.Create('Too many arguments');
|
||||
FIsOper := AIsOper;
|
||||
FOperPrec := AOperPrec;
|
||||
end;
|
||||
|
||||
function TFunction.GetDescription: string;
|
||||
begin
|
||||
Result := FDescription;
|
||||
end;
|
||||
|
||||
function TFunction.GetIsOper: boolean;
|
||||
begin
|
||||
Result := FIsOper;
|
||||
end;
|
||||
|
||||
function TFunction.GetNFunctionArg: Integer;
|
||||
begin
|
||||
Result := FNFunctionArg;
|
||||
end;
|
||||
|
||||
{ TLeftBracket }
|
||||
|
||||
function TLeftBracket.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtLeftBracket;
|
||||
end;
|
||||
|
||||
{ TExpressList }
|
||||
|
||||
function TExpressList.Compare(Key1, Key2: Pointer): Integer;
|
||||
begin
|
||||
Result := StrIComp(Pchar(Key1), Pchar(Key2));
|
||||
end;
|
||||
|
||||
function TExpressList.KeyOf(Item: Pointer): Pointer;
|
||||
begin
|
||||
Result := Pchar(TExprWord(Item).Name);
|
||||
end;
|
||||
|
||||
{ TRightBracket }
|
||||
|
||||
function TRightBracket.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtRightBracket;
|
||||
end;
|
||||
|
||||
{ TComma }
|
||||
|
||||
function TComma.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtComma;
|
||||
end;
|
||||
|
||||
{ TExprCollection }
|
||||
|
||||
procedure TExprCollection.Check;
|
||||
var
|
||||
brCount, I: Integer;
|
||||
begin
|
||||
brCount := 0;
|
||||
for I := 0 to Count - 1 do
|
||||
begin
|
||||
case TExprWord(Items[I]).VarType of
|
||||
vtLeftBracket:
|
||||
Inc(brCount);
|
||||
vtRightBracket:
|
||||
Dec(brCount);
|
||||
end;
|
||||
end;
|
||||
if brCount <> 0 then
|
||||
raise EParserException.Create('Unequal brackets');
|
||||
end;
|
||||
|
||||
procedure TExprCollection.EraseExtraBrackets;
|
||||
var
|
||||
I: Integer;
|
||||
brCount: Integer;
|
||||
begin
|
||||
if (TExprWord(Items[0]).VarType = vtLeftBracket) then
|
||||
begin
|
||||
brCount := 1;
|
||||
I := 1;
|
||||
while (I < Count) and (brCount > 0) do
|
||||
begin
|
||||
case TExprWord(Items[I]).VarType of
|
||||
vtLeftBracket:
|
||||
Inc(brCount);
|
||||
vtRightBracket:
|
||||
Dec(brCount);
|
||||
end;
|
||||
Inc(I);
|
||||
end;
|
||||
if (brCount = 0) and (I = Count) and
|
||||
(TExprWord(Items[I - 1]).VarType = vtRightBracket) then
|
||||
begin
|
||||
for I := 0 to Count - 3 do
|
||||
Items[I] := Items[I + 1];
|
||||
Count := Count - 2;
|
||||
EraseExtraBrackets; // Check if there are still too many brackets
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TExprCollection.NextOper(IStart: Integer): Integer;
|
||||
var
|
||||
brCount: Integer;
|
||||
begin
|
||||
brCount := 0;
|
||||
Result := IStart;
|
||||
while (Result < Count) and
|
||||
((brCount > 0) or (TExprWord(Items[Result]).NFunctionArg <= 0)) do
|
||||
begin
|
||||
case TExprWord(Items[Result]).VarType of
|
||||
vtLeftBracket:
|
||||
Inc(brCount);
|
||||
vtRightBracket:
|
||||
Dec(brCount);
|
||||
end;
|
||||
Inc(Result);
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TStringVariable }
|
||||
|
||||
function TStringVariable.GetAsString: string;
|
||||
begin
|
||||
if (FValue^[1] = '''') and (FValue^[Length(FValue^)] = '''') then
|
||||
Result := Copy(FValue^, 2, Length(FValue^) - 2)
|
||||
else
|
||||
Result := FValue^
|
||||
end;
|
||||
|
||||
constructor TStringVariable.Create(AName: string; AValue: PString);
|
||||
begin
|
||||
inherited Create(AName, _Variable);
|
||||
FValue := AValue;
|
||||
end;
|
||||
|
||||
function TStringVariable.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtString;
|
||||
end;
|
||||
|
||||
function TStringVariable.GetCanVary: boolean;
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
{ TLogicalStringOper }
|
||||
|
||||
constructor TLogicalStringOper.Create(AOper: string;
|
||||
ALeftArg, ARightArg: TExprWord);
|
||||
begin
|
||||
if AOper = '=' then
|
||||
FStringFunc := @_StrEq
|
||||
else if AOper = '>' then
|
||||
FStringFunc := @_StrGt
|
||||
else if AOper = '<' then
|
||||
FStringFunc := @_Strlt
|
||||
else if AOper = '>=' then
|
||||
FStringFunc := @_StrGe
|
||||
else if AOper = '<=' then
|
||||
FStringFunc := @_Strle
|
||||
else if AOper = '<>' then
|
||||
FStringFunc := @_Strne
|
||||
else if AOper = 'in' then
|
||||
FStringFunc := @_StrIn
|
||||
else
|
||||
raise EParserException.Create(AOper + ' is not a valid string operand');
|
||||
inherited Create(AOper, '', StringFunc, ALeftArg, ARightArg);
|
||||
end;
|
||||
|
||||
function TLogicalStringOper.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtBoolean;
|
||||
end;
|
||||
|
||||
{ TBooleanFunction }
|
||||
|
||||
function TBooleanFunction.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtBoolean;
|
||||
end;
|
||||
|
||||
{ TGeneratedVariable }
|
||||
|
||||
constructor TGeneratedVariable.Create(AName: string);
|
||||
begin
|
||||
inherited Create(AName, '');
|
||||
FAsString := '';
|
||||
FVarType := vtDouble;
|
||||
end;
|
||||
|
||||
function TGeneratedVariable.GetAsString: string;
|
||||
begin
|
||||
Result := FAsString;
|
||||
end;
|
||||
|
||||
function TGeneratedVariable.GetCanVary: boolean;
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function TGeneratedVariable.GetVarType: TVarType;
|
||||
begin
|
||||
Result := FVarType;
|
||||
end;
|
||||
|
||||
{ TVaryingFunction }
|
||||
|
||||
function TVaryingFunction.GetCanVary: boolean;
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
{ TBooleanConstant }
|
||||
|
||||
function TBooleanConstant.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtBoolean;
|
||||
end;
|
||||
|
||||
{ TConstant }
|
||||
|
||||
constructor TConstant.CreateAsDouble(AName, Descr: string; AValue: Double);
|
||||
begin
|
||||
FDescription := Descr;
|
||||
inherited CreateAsDouble(AName, AValue);
|
||||
end;
|
||||
|
||||
function TConstant.GetDescription: string;
|
||||
begin
|
||||
Result := FDescription;
|
||||
end;
|
||||
|
||||
{ TSimpleStringFunction }
|
||||
|
||||
constructor TSimpleStringFunction.Create(AName, Descr: string;
|
||||
AStringFunc: TStringFunc; ALeftArg, ARightArg: TExprWord);
|
||||
begin
|
||||
FStringFunc := @AStringFunc;
|
||||
FLeftArg := ALeftArg;
|
||||
FRightArg := ARightArg;
|
||||
inherited Create(AName, Descr, _StringFunc, 0)
|
||||
end;
|
||||
|
||||
function TSimpleStringFunction.Evaluate: Double;
|
||||
var
|
||||
s1, s2: string;
|
||||
begin
|
||||
s1 := FLeftArg.AsString;
|
||||
if FRightArg <> nil then
|
||||
s2 := FRightArg.AsString
|
||||
else
|
||||
s2 := '';
|
||||
Result := StringFunc(s1, s2);
|
||||
end;
|
||||
|
||||
function TSimpleStringFunction.GetCanVary: boolean;
|
||||
begin
|
||||
Result := ((FLeftArg <> nil) and FLeftArg.CanVary) or
|
||||
((FRightArg <> nil) and FRightArg.CanVary);
|
||||
end;
|
||||
{ TVaryingStringFunction }
|
||||
|
||||
function TVaryingStringFunction.GetCanVary: boolean;
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
end.
|
@@ -1,719 +0,0 @@
|
||||
unit ParseClass;
|
||||
|
||||
interface
|
||||
|
||||
uses OObjects, SysUtils;
|
||||
|
||||
const
|
||||
MaxArg = 1000;
|
||||
|
||||
const
|
||||
Nan: Double = 0 / 0;
|
||||
function isNan(const d: Double): boolean;
|
||||
|
||||
type
|
||||
TVarType = (vtDouble, vtBoolean, vtString, vtLeftBracket,
|
||||
vtRightBracket, vtComma);
|
||||
PDouble = ^Double;
|
||||
EParserException = class(Exception);
|
||||
PExpressionRec = ^TExpressionRec;
|
||||
|
||||
TExprWord = class;
|
||||
|
||||
TArgsArray = record
|
||||
Res: Double;
|
||||
Args: array [0 .. MaxArg - 1] of PDouble;
|
||||
ExprWord: TExprWord; // can be used to notify the object to update
|
||||
end;
|
||||
|
||||
TDoubleFunc = procedure(Expr: PExpressionRec);
|
||||
|
||||
TStringFunc = function(s1, s2: string): Double;
|
||||
|
||||
TExpressionRec = record
|
||||
// used both as linked tree and linked list for maximum evaluation efficiency
|
||||
Oper: TDoubleFunc;
|
||||
Next: PExpressionRec;
|
||||
Res: Double;
|
||||
ExprWord: TExprWord;
|
||||
case Byte of
|
||||
0:
|
||||
(Args: array [0 .. MaxArg - 1] of PDouble;
|
||||
// can be used to notify the object to update
|
||||
);
|
||||
1:
|
||||
(ArgList: array [0 .. MaxArg - 1] of PExpressionRec);
|
||||
end;
|
||||
|
||||
TExprCollection = class(TNoOwnerCollection)
|
||||
public
|
||||
function NextOper(IStart: Integer): Integer;
|
||||
procedure Check;
|
||||
procedure EraseExtraBrackets;
|
||||
end;
|
||||
|
||||
TExprWord = class
|
||||
private
|
||||
FName: string;
|
||||
FDoubleFunc: TDoubleFunc;
|
||||
protected
|
||||
function GetIsOper: boolean; virtual;
|
||||
function GetAsString: string; virtual;
|
||||
function GetIsVariable: boolean;
|
||||
function GetCanVary: boolean; virtual;
|
||||
function GetVarType: TVarType; virtual;
|
||||
function GetNFunctionArg: Integer; virtual;
|
||||
function GetDescription: string; virtual;
|
||||
public
|
||||
constructor Create(AName: string; ADoubleFunc: TDoubleFunc);
|
||||
function AsPointer: PDouble; virtual;
|
||||
property AsString: string read GetAsString;
|
||||
property DoubleFunc: TDoubleFunc read FDoubleFunc;
|
||||
property IsOper: boolean read GetIsOper;
|
||||
property CanVary: boolean read GetCanVary;
|
||||
property isVariable: boolean read GetIsVariable;
|
||||
property VarType: TVarType read GetVarType;
|
||||
property NFunctionArg: Integer read GetNFunctionArg;
|
||||
property Name: string read FName;
|
||||
property Description: string read GetDescription;
|
||||
end;
|
||||
|
||||
TExpressList = class(TSortedCollection)
|
||||
public
|
||||
function KeyOf(Item: Pointer): Pointer; override;
|
||||
function Compare(Key1, Key2: Pointer): Integer; override;
|
||||
end;
|
||||
|
||||
TDoubleConstant = class(TExprWord)
|
||||
private
|
||||
FValue: Double;
|
||||
public
|
||||
function AsPointer: PDouble; override;
|
||||
constructor Create(AName: string; AValue: string);
|
||||
constructor CreateAsDouble(AName: string; AValue: Double);
|
||||
// not overloaded to support older Delphi versions
|
||||
property Value: Double read FValue write FValue;
|
||||
end;
|
||||
|
||||
TConstant = class(TDoubleConstant)
|
||||
private
|
||||
FDescription: string;
|
||||
protected
|
||||
function GetDescription: string; override;
|
||||
public
|
||||
constructor CreateAsDouble(AName, Descr: string; AValue: Double);
|
||||
end;
|
||||
|
||||
TBooleanConstant = class(TDoubleConstant)
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
end;
|
||||
|
||||
TGeneratedVariable = class(TDoubleConstant)
|
||||
private
|
||||
FAsString: string;
|
||||
FVarType: TVarType;
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
function GetAsString: string; override;
|
||||
function GetCanVary: boolean; override;
|
||||
public
|
||||
constructor Create(AName: string);
|
||||
property VarType read GetVarType write FVarType;
|
||||
property AsString: string read GetAsString write FAsString;
|
||||
end;
|
||||
|
||||
TDoubleVariable = class(TExprWord)
|
||||
private
|
||||
FValue: PDouble;
|
||||
protected
|
||||
function GetCanVary: boolean; override;
|
||||
public
|
||||
function AsPointer: PDouble; override;
|
||||
constructor Create(AName: string; AValue: PDouble);
|
||||
end;
|
||||
|
||||
TStringConstant = class(TExprWord)
|
||||
private
|
||||
FValue: string;
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
function GetAsString: string; override;
|
||||
public
|
||||
constructor Create(AValue: string);
|
||||
end;
|
||||
|
||||
TLeftBracket = class(TExprWord)
|
||||
function GetVarType: TVarType; override;
|
||||
end;
|
||||
|
||||
TRightBracket = class(TExprWord)
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
end;
|
||||
|
||||
TComma = class(TExprWord)
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
end;
|
||||
|
||||
PString = ^string;
|
||||
|
||||
TStringVariable = class(TExprWord)
|
||||
private
|
||||
FValue: PString;
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
function GetAsString: string; override;
|
||||
function GetCanVary: boolean; override;
|
||||
public
|
||||
constructor Create(AName: string; AValue: PString);
|
||||
end;
|
||||
|
||||
TFunction = class(TExprWord)
|
||||
private
|
||||
FIsOper: boolean;
|
||||
FOperPrec: Integer;
|
||||
FNFunctionArg: Integer;
|
||||
FDescription: string;
|
||||
protected
|
||||
function GetDescription: string; override;
|
||||
function GetIsOper: boolean; override;
|
||||
function GetNFunctionArg: Integer; override;
|
||||
public
|
||||
constructor Create(AName, Descr: string; ADoubleFunc: TDoubleFunc;
|
||||
ANFunctionArg: Integer);
|
||||
constructor CreateOper(AName: string; ADoubleFunc: TDoubleFunc;
|
||||
ANFunctionArg: Integer; AIsOper: boolean; AOperPrec: Integer);
|
||||
property OperPrec: Integer read FOperPrec;
|
||||
end;
|
||||
|
||||
TVaryingFunction = class(TFunction)
|
||||
// Functions that can vary for ex. random generators
|
||||
// should be TVaryingFunction to be sure that they are
|
||||
// always evaluated
|
||||
protected
|
||||
function GetCanVary: boolean; override;
|
||||
end;
|
||||
|
||||
TBooleanFunction = class(TFunction)
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
end;
|
||||
|
||||
TOper = (op_eq, op_gt, op_lt, op_ge, op_le, op_in);
|
||||
|
||||
const
|
||||
ListChar = ','; { the delimiter used with the 'in' operator: e.g.,
|
||||
('a' in 'a,b') =True
|
||||
('c' in 'a,b') =False }
|
||||
|
||||
type
|
||||
TSimpleStringFunction = class(TFunction)
|
||||
private
|
||||
FStringFunc: TStringFunc;
|
||||
FLeftArg: TExprWord;
|
||||
FRightArg: TExprWord;
|
||||
protected
|
||||
function GetCanVary: boolean; override;
|
||||
public
|
||||
constructor Create(AName, Descr: string; AStringFunc: TStringFunc;
|
||||
ALeftArg, ARightArg: TExprWord);
|
||||
function Evaluate: Double;
|
||||
property StringFunc: TStringFunc read FStringFunc;
|
||||
end;
|
||||
|
||||
TVaryingStringFunction = class(TSimpleStringFunction)
|
||||
protected
|
||||
function GetCanVary: boolean; override;
|
||||
end;
|
||||
|
||||
TLogicalStringOper = class(TSimpleStringFunction)
|
||||
protected
|
||||
function GetVarType: TVarType; override;
|
||||
public
|
||||
constructor Create(AOper: string; ALeftArg: TExprWord;
|
||||
ARightArg: TExprWord);
|
||||
end;
|
||||
|
||||
procedure _Variable(Param: PExpressionRec);
|
||||
|
||||
// procedure _StringFunc(Param: PExpressionRec);
|
||||
|
||||
implementation
|
||||
|
||||
// function _StrIn(sLookfor, sData: string): Double;
|
||||
|
||||
// function _StrInt(a, b: string): Double;
|
||||
|
||||
function isNan(const d: Double): boolean;
|
||||
begin
|
||||
Result := comp(d) = comp(Nan);
|
||||
// slower alternative: CompareMem(@d, @Nan, SizeOf(Double))
|
||||
end;
|
||||
|
||||
procedure _Variable(Param: PExpressionRec);
|
||||
begin
|
||||
with Param^ do
|
||||
Res := Args[0]^;
|
||||
end;
|
||||
|
||||
procedure _StringFunc(Param: PExpressionRec);
|
||||
begin
|
||||
with Param^ do
|
||||
Res := TSimpleStringFunction(ExprWord).Evaluate;
|
||||
end;
|
||||
|
||||
function _StrInt(a, b: string): Double;
|
||||
begin
|
||||
Result := StrToInt(a);
|
||||
end;
|
||||
|
||||
function _StrEq(s1, s2: string): Double;
|
||||
begin
|
||||
Result := Byte(s1 = s2);
|
||||
end;
|
||||
|
||||
function _StrGt(s1, s2: string): Double;
|
||||
begin
|
||||
Result := Byte(s1 > s2);
|
||||
end;
|
||||
|
||||
function _Strlt(s1, s2: string): Double;
|
||||
begin
|
||||
Result := Byte(s1 < s2);
|
||||
end;
|
||||
|
||||
function _StrGe(s1, s2: string): Double;
|
||||
begin
|
||||
Result := Byte(s1 >= s2);
|
||||
end;
|
||||
|
||||
function _Strle(s1, s2: string): Double;
|
||||
begin
|
||||
Result := Byte(s1 <= s2);
|
||||
end;
|
||||
|
||||
function _Strne(s1, s2: string): Double;
|
||||
begin
|
||||
Result := Byte(s1 <> s2);
|
||||
end;
|
||||
|
||||
function _StrIn(sLookfor, sData: string): Double;
|
||||
var
|
||||
loop: Integer;
|
||||
subString: string;
|
||||
begin
|
||||
Result := 0;
|
||||
loop := pos(ListChar, sData);
|
||||
while loop > 0 do
|
||||
begin
|
||||
subString := Copy(sData, 1, loop - 1);
|
||||
sData := Copy(sData, loop + 1, Length(sData));
|
||||
if subString = sLookfor then
|
||||
begin
|
||||
Result := 1;
|
||||
break;
|
||||
end;
|
||||
loop := pos(ListChar, sData);
|
||||
end;
|
||||
if sLookfor = sData then
|
||||
Result := 1;
|
||||
end;
|
||||
|
||||
{ TExpressionWord }
|
||||
|
||||
function TExprWord.AsPointer: PDouble;
|
||||
begin
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
constructor TExprWord.Create(AName: string; ADoubleFunc: TDoubleFunc);
|
||||
begin
|
||||
FName := LowerCase(AName);
|
||||
FDoubleFunc := ADoubleFunc;
|
||||
end;
|
||||
|
||||
function TExprWord.GetAsString: string;
|
||||
begin
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
function TExprWord.GetCanVary: boolean;
|
||||
begin
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
function TExprWord.GetDescription: string;
|
||||
begin
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
function TExprWord.GetIsOper: boolean;
|
||||
begin
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
function TExprWord.GetIsVariable: boolean;
|
||||
begin
|
||||
Result := @FDoubleFunc = @_Variable
|
||||
end;
|
||||
|
||||
function TExprWord.GetNFunctionArg: Integer;
|
||||
begin
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
function TExprWord.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtDouble;
|
||||
end;
|
||||
|
||||
{ TDoubleConstant }
|
||||
|
||||
function TDoubleConstant.AsPointer: PDouble;
|
||||
begin
|
||||
Result := @FValue;
|
||||
end;
|
||||
|
||||
constructor TDoubleConstant.Create(AName, AValue: string);
|
||||
begin
|
||||
inherited Create(AName, _Variable);
|
||||
if AValue <> '' then
|
||||
FValue := StrToFloat(AValue)
|
||||
else
|
||||
FValue := Nan;
|
||||
end;
|
||||
|
||||
constructor TDoubleConstant.CreateAsDouble(AName: string; AValue: Double);
|
||||
begin
|
||||
inherited Create(AName, _Variable);
|
||||
FValue := AValue;
|
||||
end;
|
||||
|
||||
{ TStringConstant }
|
||||
|
||||
function TStringConstant.GetAsString: string;
|
||||
begin
|
||||
Result := FValue;
|
||||
end;
|
||||
|
||||
constructor TStringConstant.Create(AValue: string);
|
||||
begin
|
||||
inherited Create(AValue, _Variable);
|
||||
if (AValue[1] = '''') and (AValue[Length(AValue)] = '''') then
|
||||
FValue := Copy(AValue, 2, Length(AValue) - 2)
|
||||
else
|
||||
FValue := AValue;
|
||||
end;
|
||||
|
||||
function TStringConstant.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtString;
|
||||
end;
|
||||
|
||||
{ TDoubleVariable }
|
||||
|
||||
function TDoubleVariable.AsPointer: PDouble;
|
||||
begin
|
||||
Result := FValue;
|
||||
end;
|
||||
|
||||
constructor TDoubleVariable.Create(AName: string; AValue: PDouble);
|
||||
begin
|
||||
inherited Create(AName, _Variable);
|
||||
FValue := AValue;
|
||||
end;
|
||||
|
||||
function TDoubleVariable.GetCanVary: boolean;
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
{ TFunction }
|
||||
|
||||
constructor TFunction.Create(AName, Descr: string; ADoubleFunc: TDoubleFunc;
|
||||
ANFunctionArg: Integer);
|
||||
begin
|
||||
FDescription := Descr;
|
||||
CreateOper(AName, ADoubleFunc, ANFunctionArg, False, 0);
|
||||
// to increase compatibility don't use default parameters
|
||||
end;
|
||||
|
||||
constructor TFunction.CreateOper(AName: string; ADoubleFunc: TDoubleFunc;
|
||||
ANFunctionArg: Integer; AIsOper: boolean; AOperPrec: Integer);
|
||||
begin
|
||||
inherited Create(AName, ADoubleFunc);
|
||||
FNFunctionArg := ANFunctionArg;
|
||||
if FNFunctionArg > MaxArg then
|
||||
raise EParserException.Create('Too many arguments');
|
||||
FIsOper := AIsOper;
|
||||
FOperPrec := AOperPrec;
|
||||
end;
|
||||
|
||||
function TFunction.GetDescription: string;
|
||||
begin
|
||||
Result := FDescription;
|
||||
end;
|
||||
|
||||
function TFunction.GetIsOper: boolean;
|
||||
begin
|
||||
Result := FIsOper;
|
||||
end;
|
||||
|
||||
function TFunction.GetNFunctionArg: Integer;
|
||||
begin
|
||||
Result := FNFunctionArg;
|
||||
end;
|
||||
|
||||
{ TLeftBracket }
|
||||
|
||||
function TLeftBracket.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtLeftBracket;
|
||||
end;
|
||||
|
||||
{ TExpressList }
|
||||
|
||||
function TExpressList.Compare(Key1, Key2: Pointer): Integer;
|
||||
begin
|
||||
Result := StrIComp(Pchar(Key1), Pchar(Key2));
|
||||
end;
|
||||
|
||||
function TExpressList.KeyOf(Item: Pointer): Pointer;
|
||||
begin
|
||||
Result := Pchar(TExprWord(Item).Name);
|
||||
end;
|
||||
|
||||
{ TRightBracket }
|
||||
|
||||
function TRightBracket.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtRightBracket;
|
||||
end;
|
||||
|
||||
{ TComma }
|
||||
|
||||
function TComma.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtComma;
|
||||
end;
|
||||
|
||||
{ TExprCollection }
|
||||
|
||||
procedure TExprCollection.Check;
|
||||
var
|
||||
brCount, I: Integer;
|
||||
begin
|
||||
brCount := 0;
|
||||
for I := 0 to Count - 1 do
|
||||
begin
|
||||
case TExprWord(Items[I]).VarType of
|
||||
vtLeftBracket:
|
||||
Inc(brCount);
|
||||
vtRightBracket:
|
||||
Dec(brCount);
|
||||
end;
|
||||
end;
|
||||
if brCount <> 0 then
|
||||
raise EParserException.Create('Unequal brackets');
|
||||
end;
|
||||
|
||||
procedure TExprCollection.EraseExtraBrackets;
|
||||
var
|
||||
I: Integer;
|
||||
brCount: Integer;
|
||||
begin
|
||||
if (TExprWord(Items[0]).VarType = vtLeftBracket) then
|
||||
begin
|
||||
brCount := 1;
|
||||
I := 1;
|
||||
while (I < Count) and (brCount > 0) do
|
||||
begin
|
||||
case TExprWord(Items[I]).VarType of
|
||||
vtLeftBracket:
|
||||
Inc(brCount);
|
||||
vtRightBracket:
|
||||
Dec(brCount);
|
||||
end;
|
||||
Inc(I);
|
||||
end;
|
||||
if (brCount = 0) and (I = Count) and
|
||||
(TExprWord(Items[I - 1]).VarType = vtRightBracket) then
|
||||
begin
|
||||
for I := 0 to Count - 3 do
|
||||
Items[I] := Items[I + 1];
|
||||
Count := Count - 2;
|
||||
EraseExtraBrackets; // Check if there are still too many brackets
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TExprCollection.NextOper(IStart: Integer): Integer;
|
||||
var
|
||||
brCount: Integer;
|
||||
begin
|
||||
brCount := 0;
|
||||
Result := IStart;
|
||||
while (Result < Count) and
|
||||
((brCount > 0) or (TExprWord(Items[Result]).NFunctionArg <= 0)) do
|
||||
begin
|
||||
case TExprWord(Items[Result]).VarType of
|
||||
vtLeftBracket:
|
||||
Inc(brCount);
|
||||
vtRightBracket:
|
||||
Dec(brCount);
|
||||
end;
|
||||
Inc(Result);
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TStringVariable }
|
||||
|
||||
function TStringVariable.GetAsString: string;
|
||||
begin
|
||||
if (FValue^[1] = '''') and (FValue^[Length(FValue^)] = '''') then
|
||||
Result := Copy(FValue^, 2, Length(FValue^) - 2)
|
||||
else
|
||||
Result := FValue^
|
||||
end;
|
||||
|
||||
constructor TStringVariable.Create(AName: string; AValue: PString);
|
||||
begin
|
||||
inherited Create(AName, _Variable);
|
||||
FValue := AValue;
|
||||
end;
|
||||
|
||||
function TStringVariable.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtString;
|
||||
end;
|
||||
|
||||
function TStringVariable.GetCanVary: boolean;
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
{ TLogicalStringOper }
|
||||
|
||||
constructor TLogicalStringOper.Create(AOper: string;
|
||||
ALeftArg, ARightArg: TExprWord);
|
||||
begin
|
||||
if AOper = '=' then
|
||||
FStringFunc := @_StrEq
|
||||
else if AOper = '>' then
|
||||
FStringFunc := @_StrGt
|
||||
else if AOper = '<' then
|
||||
FStringFunc := @_Strlt
|
||||
else if AOper = '>=' then
|
||||
FStringFunc := @_StrGe
|
||||
else if AOper = '<=' then
|
||||
FStringFunc := @_Strle
|
||||
else if AOper = '<>' then
|
||||
FStringFunc := @_Strne
|
||||
else if AOper = 'in' then
|
||||
FStringFunc := @_StrIn
|
||||
else
|
||||
raise EParserException.Create(AOper + ' is not a valid string operand');
|
||||
inherited Create(AOper, '', StringFunc, ALeftArg, ARightArg);
|
||||
end;
|
||||
|
||||
function TLogicalStringOper.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtBoolean;
|
||||
end;
|
||||
|
||||
{ TBooleanFunction }
|
||||
|
||||
function TBooleanFunction.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtBoolean;
|
||||
end;
|
||||
|
||||
{ TGeneratedVariable }
|
||||
|
||||
constructor TGeneratedVariable.Create(AName: string);
|
||||
begin
|
||||
inherited Create(AName, '');
|
||||
FAsString := '';
|
||||
FVarType := vtDouble;
|
||||
end;
|
||||
|
||||
function TGeneratedVariable.GetAsString: string;
|
||||
begin
|
||||
Result := FAsString;
|
||||
end;
|
||||
|
||||
function TGeneratedVariable.GetCanVary: boolean;
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function TGeneratedVariable.GetVarType: TVarType;
|
||||
begin
|
||||
Result := FVarType;
|
||||
end;
|
||||
|
||||
{ TVaryingFunction }
|
||||
|
||||
function TVaryingFunction.GetCanVary: boolean;
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
{ TBooleanConstant }
|
||||
|
||||
function TBooleanConstant.GetVarType: TVarType;
|
||||
begin
|
||||
Result := vtBoolean;
|
||||
end;
|
||||
|
||||
{ TConstant }
|
||||
|
||||
constructor TConstant.CreateAsDouble(AName, Descr: string; AValue: Double);
|
||||
begin
|
||||
FDescription := Descr;
|
||||
inherited CreateAsDouble(AName, AValue);
|
||||
end;
|
||||
|
||||
function TConstant.GetDescription: string;
|
||||
begin
|
||||
Result := FDescription;
|
||||
end;
|
||||
|
||||
{ TSimpleStringFunction }
|
||||
|
||||
constructor TSimpleStringFunction.Create(AName, Descr: string;
|
||||
AStringFunc: TStringFunc; ALeftArg, ARightArg: TExprWord);
|
||||
begin
|
||||
FStringFunc := @AStringFunc;
|
||||
FLeftArg := ALeftArg;
|
||||
FRightArg := ARightArg;
|
||||
inherited Create(AName, Descr, _StringFunc, 0)
|
||||
end;
|
||||
|
||||
function TSimpleStringFunction.Evaluate: Double;
|
||||
var
|
||||
s1, s2: string;
|
||||
begin
|
||||
s1 := FLeftArg.AsString;
|
||||
if FRightArg <> nil then
|
||||
s2 := FRightArg.AsString
|
||||
else
|
||||
s2 := '';
|
||||
Result := StringFunc(s1, s2);
|
||||
end;
|
||||
|
||||
function TSimpleStringFunction.GetCanVary: boolean;
|
||||
begin
|
||||
Result := ((FLeftArg <> nil) and FLeftArg.CanVary) or
|
||||
((FRightArg <> nil) and FRightArg.CanVary);
|
||||
end;
|
||||
{ TVaryingStringFunction }
|
||||
|
||||
function TVaryingStringFunction.GetCanVary: boolean;
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
end.
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,203 +0,0 @@
|
||||
unit OObjects;
|
||||
|
||||
interface
|
||||
|
||||
uses Classes;
|
||||
|
||||
const
|
||||
|
||||
{ TOCollection interfaces between OWL TCollection and VCL TList }
|
||||
MaxCollectionSize = Maxint div (SizeOf(Integer) * 2);
|
||||
|
||||
type
|
||||
TOCollection = class(TList)
|
||||
public
|
||||
constructor Create(ACapacity: Integer);
|
||||
procedure AtFree(Index: Integer);
|
||||
procedure FreeAll;
|
||||
procedure DoFree(Item: Pointer);
|
||||
procedure FreeItem(Item: Pointer); virtual;
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
TNoOwnerCollection = class(TOCollection)
|
||||
public
|
||||
procedure FreeItem(Item: Pointer); override;
|
||||
end;
|
||||
|
||||
{ TSortedCollection object }
|
||||
|
||||
TSortedCollection = class(TOCollection)
|
||||
public
|
||||
Duplicates: Boolean;
|
||||
constructor Create(ACapacity: Integer);
|
||||
function Compare(Key1, Key2: Pointer): Integer; virtual; abstract;
|
||||
function IndexOf(Item: Pointer): Integer; virtual;
|
||||
procedure Add(Item: Pointer); virtual;
|
||||
procedure AddReplace(Item: Pointer); virtual;
|
||||
{ if duplicate then replace the duplicate else add }
|
||||
function KeyOf(Item: Pointer): Pointer; virtual;
|
||||
function Search(Key: Pointer; var Index: Integer): Boolean; virtual;
|
||||
end;
|
||||
|
||||
{ TStrCollection object }
|
||||
|
||||
TStrCollection = class(TSortedCollection)
|
||||
public
|
||||
function Compare(Key1, Key2: Pointer): Integer; override;
|
||||
procedure FreeItem(Item: Pointer); override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses SysUtils;
|
||||
|
||||
constructor TOCollection.Create(ACapacity: Integer);
|
||||
begin
|
||||
inherited Create;
|
||||
SetCapacity(ACapacity);
|
||||
{ Delta is automatic in TList }
|
||||
end;
|
||||
|
||||
destructor TOCollection.Destroy;
|
||||
begin
|
||||
FreeAll;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TOCollection.AtFree(Index: Integer);
|
||||
var
|
||||
Item: Pointer;
|
||||
begin
|
||||
Item := Items[Index];
|
||||
Delete(Index);
|
||||
FreeItem(Item);
|
||||
end;
|
||||
|
||||
procedure TOCollection.FreeAll;
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
try
|
||||
for I := 0 to Count - 1 do
|
||||
FreeItem(Items[I]);
|
||||
finally
|
||||
Count := 0;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TOCollection.DoFree(Item: Pointer);
|
||||
begin
|
||||
AtFree(IndexOf(Item));
|
||||
end;
|
||||
|
||||
procedure TOCollection.FreeItem(Item: Pointer);
|
||||
begin
|
||||
if (Item <> nil) then
|
||||
with TObject(Item) as TObject do
|
||||
Free;
|
||||
end;
|
||||
|
||||
{ ----------------------------------------------------------------virtual;
|
||||
Implementing TNoOwnerCollection
|
||||
----------------------------------------------------------------- }
|
||||
|
||||
procedure TNoOwnerCollection.FreeItem(Item: Pointer);
|
||||
begin
|
||||
end;
|
||||
|
||||
{ TSortedCollection }
|
||||
|
||||
{$IFDEF maxComp}
|
||||
|
||||
constructor TSortedCollection.Create(ACapacity, ADelta: Integer);
|
||||
begin
|
||||
inherited Create(ACapacity, ADelta);
|
||||
Duplicates := False;
|
||||
end;
|
||||
{$ELSE}
|
||||
|
||||
constructor TSortedCollection.Create(ACapacity: Integer);
|
||||
begin
|
||||
inherited Create(ACapacity);
|
||||
Duplicates := False;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
function TSortedCollection.IndexOf(Item: Pointer): Integer;
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
IndexOf := -1;
|
||||
if Search(KeyOf(Item), I) then
|
||||
begin
|
||||
if Duplicates then
|
||||
while (I < Count) and (Item <> Items[I]) do
|
||||
Inc(I);
|
||||
if I < Count then
|
||||
IndexOf := I;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSortedCollection.AddReplace(Item: Pointer);
|
||||
var
|
||||
Index: Integer;
|
||||
begin
|
||||
if Search(KeyOf(Item), Index) then
|
||||
Delete(Index);
|
||||
Add(Item);
|
||||
end;
|
||||
|
||||
procedure TSortedCollection.Add(Item: Pointer);
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
if not Search(KeyOf(Item), I) or Duplicates then
|
||||
Insert(I, Item);
|
||||
end;
|
||||
|
||||
function TSortedCollection.KeyOf(Item: Pointer): Pointer;
|
||||
begin
|
||||
KeyOf := Item;
|
||||
end;
|
||||
|
||||
function TSortedCollection.Search(Key: Pointer; var Index: Integer): Boolean;
|
||||
var
|
||||
L, H, I, C: Integer;
|
||||
begin
|
||||
Search := False;
|
||||
L := 0;
|
||||
H := Count - 1;
|
||||
while L <= H do
|
||||
begin
|
||||
I := (L + H) shr 1;
|
||||
C := Compare(KeyOf(Items[I]), Key);
|
||||
if C < 0 then
|
||||
L := I + 1
|
||||
else
|
||||
begin
|
||||
H := I - 1;
|
||||
if C = 0 then
|
||||
begin
|
||||
Search := True;
|
||||
if not Duplicates then
|
||||
L := I;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
Index := L;
|
||||
end;
|
||||
|
||||
{ TStrCollection }
|
||||
|
||||
function TStrCollection.Compare(Key1, Key2: Pointer): Integer;
|
||||
begin
|
||||
Compare := StrComp(PAnsiChar(Key1), PAnsiChar(Key2));
|
||||
end;
|
||||
|
||||
procedure TStrCollection.FreeItem(Item: Pointer);
|
||||
begin
|
||||
StrDispose(PAnsiChar(Item));
|
||||
end;
|
||||
|
||||
end.
|
Reference in New Issue
Block a user