* Add support for currency type

git-svn-id: trunk@38523 -
This commit is contained in:
michael 2018-03-14 10:54:42 +00:00
parent 3a78ff1ee4
commit c3414c6100
2 changed files with 597 additions and 123 deletions

View File

@ -85,7 +85,7 @@ Type
EExprScanner = Class(Exception); EExprScanner = Class(Exception);
TResultType = (rtBoolean,rtInteger,rtFloat,rtDateTime,rtString); TResultType = (rtBoolean,rtInteger,rtFloat,rtDateTime,rtString,rtCurrency);
TResultTypes = set of TResultType; TResultTypes = set of TResultType;
TFPExpressionResult = record TFPExpressionResult = record
@ -94,6 +94,7 @@ Type
rtBoolean : (ResBoolean : Boolean); rtBoolean : (ResBoolean : Boolean);
rtInteger : (ResInteger : Int64); rtInteger : (ResInteger : Int64);
rtFloat : (ResFloat : TExprFloat); rtFloat : (ResFloat : TExprFloat);
rtCurrency : (ResCurrency : Currency);
rtDateTime : (ResDateTime : TDatetime); rtDateTime : (ResDateTime : TDatetime);
rtString : (); rtString : ();
end; end;
@ -389,12 +390,21 @@ Type
end; end;
{ TIntToFloatNode } { TIntToFloatNode }
TIntToFloatNode = Class(TIntConvertNode) TIntToFloatNode = Class(TIntConvertNode)
Public Public
Function NodeType : TResultType; override; Function NodeType : TResultType; override;
Procedure GetNodeValue(var Result : TFPExpressionResult); override; Procedure GetNodeValue(var Result : TFPExpressionResult); override;
end; end;
{ TIntToCurrencyNode }
TIntToCurrencyNode = Class(TIntConvertNode)
Public
Function NodeType : TResultType; override;
Procedure GetNodeValue(var Result : TFPExpressionResult); override;
end;
{ TIntToDateTimeNode } { TIntToDateTimeNode }
TIntToDateTimeNode = Class(TIntConvertNode) TIntToDateTimeNode = Class(TIntConvertNode)
@ -412,6 +422,34 @@ Type
Procedure GetNodeValue(var Result : TFPExpressionResult); override; Procedure GetNodeValue(var Result : TFPExpressionResult); override;
end; end;
{ TFloatToCurrencyNode }
TFloatToCurrencyNode = Class(TFPConvertNode)
Public
Procedure Check; override;
Function NodeType : TResultType; override;
Procedure GetNodeValue(var Result : TFPExpressionResult); override;
end;
{ TCurrencyToDateTimeNode }
TCurrencyToDateTimeNode = Class(TFPConvertNode)
Public
Procedure Check; override;
Function NodeType : TResultType; override;
Procedure GetNodeValue(var Result : TFPExpressionResult); override;
end;
{ TCurrencyToFloatNode }
TCurrencyToFloatNode = Class(TFPConvertNode)
Public
Procedure Check; override;
Function NodeType : TResultType; override;
Procedure GetNodeValue(var Result : TFPExpressionResult); override;
end;
{ TFPNegateOperation } { TFPNegateOperation }
TFPNegateOperation = Class(TFPUnaryOperator) TFPNegateOperation = Class(TFPUnaryOperator)
@ -433,6 +471,7 @@ Type
Constructor CreateDateTime(AValue : TDateTime); Constructor CreateDateTime(AValue : TDateTime);
Constructor CreateFloat(AValue : TExprFloat); Constructor CreateFloat(AValue : TExprFloat);
Constructor CreateBoolean(AValue : Boolean); Constructor CreateBoolean(AValue : Boolean);
constructor CreateCurrency(AValue: Currency);
Procedure Check; override; Procedure Check; override;
Function NodeType : TResultType; override; Function NodeType : TResultType; override;
Procedure GetNodeValue(var Result : TFPExpressionResult); override; Procedure GetNodeValue(var Result : TFPExpressionResult); override;
@ -465,6 +504,7 @@ Type
function GetAsBoolean: Boolean; function GetAsBoolean: Boolean;
function GetAsDateTime: TDateTime; function GetAsDateTime: TDateTime;
function GetAsFloat: TExprFloat; function GetAsFloat: TExprFloat;
function GetAsCurrency : Currency;
function GetAsInteger: Int64; function GetAsInteger: Int64;
function GetAsString: String; function GetAsString: String;
function GetResultType: TResultType; function GetResultType: TResultType;
@ -473,6 +513,7 @@ Type
procedure SetAsBoolean(const AValue: Boolean); procedure SetAsBoolean(const AValue: Boolean);
procedure SetAsDateTime(const AValue: TDateTime); procedure SetAsDateTime(const AValue: TDateTime);
procedure SetAsFloat(const AValue: TExprFloat); procedure SetAsFloat(const AValue: TExprFloat);
procedure SetAsCurrency(const AValue: Currency);
procedure SetAsInteger(const AValue: Int64); procedure SetAsInteger(const AValue: Int64);
procedure SetAsString(const AValue: String); procedure SetAsString(const AValue: String);
procedure SetName(const AValue: ShortString); procedure SetName(const AValue: ShortString);
@ -487,6 +528,7 @@ Type
Procedure Assign(Source : TPersistent); override; Procedure Assign(Source : TPersistent); override;
Function EventBasedVariable : Boolean; Inline; Function EventBasedVariable : Boolean; Inline;
Property AsFloat : TExprFloat Read GetAsFloat Write SetAsFloat; Property AsFloat : TExprFloat Read GetAsFloat Write SetAsFloat;
Property AsCurrency : Currency Read GetAsCurrency Write SetAsCurrency;
Property AsInteger : Int64 Read GetAsInteger Write SetAsInteger; Property AsInteger : Int64 Read GetAsInteger Write SetAsInteger;
Property AsString : String Read GetAsString Write SetAsString; Property AsString : String Read GetAsString Write SetAsString;
Property AsBoolean : Boolean Read GetAsBoolean Write SetAsBoolean; Property AsBoolean : Boolean Read GetAsBoolean Write SetAsBoolean;
@ -539,6 +581,7 @@ Type
Function AddBooleanVariable(Const AName : ShortString; AValue : Boolean) : TFPExprIdentifierDef; Function AddBooleanVariable(Const AName : ShortString; AValue : Boolean) : TFPExprIdentifierDef;
Function AddIntegerVariable(Const AName : ShortString; AValue : Integer) : TFPExprIdentifierDef; Function AddIntegerVariable(Const AName : ShortString; AValue : Integer) : TFPExprIdentifierDef;
Function AddFloatVariable(Const AName : ShortString; AValue : TExprFloat) : TFPExprIdentifierDef; Function AddFloatVariable(Const AName : ShortString; AValue : TExprFloat) : TFPExprIdentifierDef;
Function AddCurrencyVariable(Const AName : ShortString; AValue : Currency) : TFPExprIdentifierDef;
Function AddStringVariable(Const AName : ShortString; AValue : String) : TFPExprIdentifierDef; Function AddStringVariable(Const AName : ShortString; AValue : String) : TFPExprIdentifierDef;
Function AddDateTimeVariable(Const AName : ShortString; AValue : TDateTime) : TFPExprIdentifierDef; Function AddDateTimeVariable(Const AName : ShortString; AValue : TDateTime) : TFPExprIdentifierDef;
Function AddFunction(Const AName : ShortString; Const AResultType : Char; Const AParamTypes : String; ACallBack : TFPExprFunctionCallBack) : TFPExprIdentifierDef; Function AddFunction(Const AName : ShortString; Const AResultType : Char; Const AParamTypes : String; ACallBack : TFPExprFunctionCallBack) : TFPExprIdentifierDef;
@ -576,6 +619,7 @@ Type
FargumentParams : TExprParameterArray; FargumentParams : TExprParameterArray;
Protected Protected
Procedure CalcParams; Procedure CalcParams;
function ConvertArgument(aIndex: Integer; aNode: TFPExprNode; aType: TResultType): TFPExprNode; virtual;
Public Public
Procedure Check; override; Procedure Check; override;
Constructor CreateFunction(AID : TFPExprIdentifierDef; Const Args : TExprArgumentArray); virtual; Constructor CreateFunction(AID : TFPExprIdentifierDef; Const Args : TExprArgumentArray); virtual;
@ -622,6 +666,7 @@ Type
TAggregateSum = Class(TAggregateExpr) TAggregateSum = Class(TAggregateExpr)
Public Public
function ConvertArgument(aIndex: Integer; aNode: TFPExprNode; aType: TResultType): TFPExprNode; override;
Procedure InitAggregate; override; Procedure InitAggregate; override;
Procedure UpdateAggregate; override; Procedure UpdateAggregate; override;
end; end;
@ -679,10 +724,10 @@ Type
FHashList : TFPHashObjectlist; FHashList : TFPHashObjectlist;
FDirty : Boolean; FDirty : Boolean;
procedure CheckEOF; procedure CheckEOF;
function ConvertNode(Todo: TFPExprNode; ToType: TResultType): TFPExprNode;
function GetAsBoolean: Boolean; function GetAsBoolean: Boolean;
function GetAsDateTime: TDateTime; function GetAsDateTime: TDateTime;
function GetAsFloat: TExprFloat; function GetAsFloat: TExprFloat;
function GetAsCurrency: Currency;
function GetAsInteger: Int64; function GetAsInteger: Int64;
function GetAsString: String; function GetAsString: String;
function MatchNodes(Todo, Match: TFPExprNode): TFPExprNode; function MatchNodes(Todo, Match: TFPExprNode): TFPExprNode;
@ -693,6 +738,8 @@ Type
procedure ParserError(Msg: String); procedure ParserError(Msg: String);
procedure SetExpression(const AValue: String); virtual; procedure SetExpression(const AValue: String); virtual;
Procedure CheckResultType(Const Res :TFPExpressionResult; AType : TResultType); inline; Procedure CheckResultType(Const Res :TFPExpressionResult; AType : TResultType); inline;
Procedure CheckResultTypes(Const Res :TFPExpressionResult; ATypes : TResultTypes); inline;
Class function ConvertNode(Todo: TFPExprNode; ToType: TResultType): TFPExprNode;
class Function BuiltinsManager : TExprBuiltInManager; class Function BuiltinsManager : TExprBuiltInManager;
Function Level1 : TFPExprNode; Function Level1 : TFPExprNode;
Function Level2 : TFPExprNode; Function Level2 : TFPExprNode;
@ -714,7 +761,7 @@ Type
Destructor Destroy; override; Destructor Destroy; override;
Function IdentifierByName(const AName : ShortString) : TFPExprIdentifierDef; virtual; Function IdentifierByName(const AName : ShortString) : TFPExprIdentifierDef; virtual;
Procedure Clear; Procedure Clear;
Procedure EvaluateExpression(Var Result : TFPExpressionResult); Procedure EvaluateExpression(Out Result : TFPExpressionResult);
function ExtractNode(var N: TFPExprNode): Boolean; function ExtractNode(var N: TFPExprNode): Boolean;
Function Evaluate : TFPExpressionResult; Function Evaluate : TFPExpressionResult;
Function ResultType : TResultType; Function ResultType : TResultType;
@ -722,6 +769,7 @@ Type
Procedure InitAggregate; Procedure InitAggregate;
Procedure UpdateAggregate; Procedure UpdateAggregate;
Property AsFloat : TExprFloat Read GetAsFloat; Property AsFloat : TExprFloat Read GetAsFloat;
Property AsCurrency : Currency Read GetAsCurrency;
Property AsInteger : Int64 Read GetAsInteger; Property AsInteger : Int64 Read GetAsInteger;
Property AsString : String Read GetAsString; Property AsString : String Read GetAsString;
Property AsBoolean : Boolean Read GetAsBoolean; Property AsBoolean : Boolean Read GetAsBoolean;
@ -752,6 +800,7 @@ Type
Function AddBooleanVariable(Const ACategory : TBuiltInCategory; Const AName : ShortString; AValue : Boolean) : TFPBuiltInExprIdentifierDef; Function AddBooleanVariable(Const ACategory : TBuiltInCategory; Const AName : ShortString; AValue : Boolean) : TFPBuiltInExprIdentifierDef;
Function AddIntegerVariable(Const ACategory : TBuiltInCategory; Const AName : ShortString; AValue : Integer) : TFPBuiltInExprIdentifierDef; Function AddIntegerVariable(Const ACategory : TBuiltInCategory; Const AName : ShortString; AValue : Integer) : TFPBuiltInExprIdentifierDef;
Function AddFloatVariable(Const ACategory : TBuiltInCategory; Const AName : ShortString; AValue : TExprFloat) : TFPBuiltInExprIdentifierDef; Function AddFloatVariable(Const ACategory : TBuiltInCategory; Const AName : ShortString; AValue : TExprFloat) : TFPBuiltInExprIdentifierDef;
Function AddCurrencyVariable(Const ACategory : TBuiltInCategory; Const AName : ShortString; AValue : Currency) : TFPBuiltInExprIdentifierDef;
Function AddStringVariable(Const ACategory : TBuiltInCategory; Const AName : ShortString; AValue : String) : TFPBuiltInExprIdentifierDef; Function AddStringVariable(Const ACategory : TBuiltInCategory; Const AName : ShortString; AValue : String) : TFPBuiltInExprIdentifierDef;
Function AddDateTimeVariable(Const ACategory : TBuiltInCategory; Const AName : ShortString; AValue : TDateTime) : TFPBuiltInExprIdentifierDef; Function AddDateTimeVariable(Const ACategory : TBuiltInCategory; Const AName : ShortString; AValue : TDateTime) : TFPBuiltInExprIdentifierDef;
Function AddFunction(Const ACategory : TBuiltInCategory; Const AName : ShortString; Const AResultType : Char; Const AParamTypes : String; ACallBack : TFPExprFunctionCallBack) : TFPBuiltInExprIdentifierDef; Function AddFunction(Const ACategory : TBuiltInCategory; Const AName : ShortString; Const AResultType : Char; Const AParamTypes : String; ACallBack : TFPExprFunctionCallBack) : TFPBuiltInExprIdentifierDef;
@ -877,6 +926,7 @@ begin
'B' : Result:=rtBoolean; 'B' : Result:=rtBoolean;
'I' : Result:=rtInteger; 'I' : Result:=rtInteger;
'F' : Result:=rtFloat; 'F' : Result:=rtFloat;
'C' : Result:=rtCurrency;
else else
RaiseParserError(SErrInvalidResultCharacter,[C]); RaiseParserError(SErrInvalidResultCharacter,[C]);
end; end;
@ -899,6 +949,39 @@ begin
FreeAndNil(Builtins); FreeAndNil(Builtins);
end; end;
{ TFloatToCurrencyNode }
procedure TFloatToCurrencyNode.Check;
begin
CheckNodeType(Operand,[rtFloat]);
end;
function TFloatToCurrencyNode.NodeType: TResultType;
begin
Result:=rtCurrency;
end;
procedure TFloatToCurrencyNode.GetNodeValue(var Result: TFPExpressionResult);
begin
Operand.GetNodeValue(Result);
Result.ResultType:=rtCurrency;
Result.ResCurrency:=Result.ResFloat;
end;
{ TIntToCurrencyNode }
function TIntToCurrencyNode.NodeType: TResultType;
begin
Result:=rtCurrency;
end;
procedure TIntToCurrencyNode.GetNodeValue(var Result: TFPExpressionResult);
begin
Operand.GetNodeValue(Result);
Result.ResCurrency:=Result.ResInteger;
Result.ResultType:=rtCurrency;
end;
{ TFPModuloOperation } { TFPModuloOperation }
procedure TFPModuloOperation.Check; procedure TFPModuloOperation.Check;
@ -936,47 +1019,16 @@ procedure TAggregateMax.InitAggregate;
begin begin
inherited InitAggregate; inherited InitAggregate;
FFirst:=True; FFirst:=True;
FResult.ResultType:=rtFloat; FResult.ResultType:=FArgumentNodes[0].NodeType;
FResult.resFloat:=0; Case FResult.ResultType of
rtFloat : FResult.resFloat:=0.0;
rtCurrency : FResult.resCurrency:=0.0;
rtInteger : FResult.resInteger:=0;
end;
end; end;
procedure TAggregateMax.UpdateAggregate; procedure TAggregateMax.UpdateAggregate;
Var
OK : Boolean;
N : TFPExpressionResult;
begin
FArgumentNodes[0].GetNodeValue(N);
if FFirst then
begin
FFirst:=False;
OK:=True;
end
else
Case N.ResultType of
rtFloat: OK:=N.ResFloat>FResult.ResFloat;
rtinteger: OK:=N.ResInteger>FResult.ResFloat;
end;
if OK then
Case N.ResultType of
rtFloat: FResult.ResFloat:=N.ResFloat;
rtinteger: FResult.ResFloat:=N.ResInteger;
end;
end;
{ TAggregateMin }
procedure TAggregateMin.InitAggregate;
begin
inherited InitAggregate;
FFirst:=True;
FResult.ResultType:=rtFloat;
FResult.resFloat:=0;
end;
procedure TAggregateMin.UpdateAggregate;
Var Var
OK : Boolean; OK : Boolean;
N : TFPExpressionResult; N : TFPExpressionResult;
@ -989,14 +1041,57 @@ begin
FFirst:=False; FFirst:=False;
OK:=True; OK:=True;
end end
else
Case N.ResultType of
rtFloat: OK:=N.ResFloat>FResult.ResFloat;
rtCurrency: OK:=N.ResCurrency>FResult.ResCurrency;
rtinteger: OK:=N.ResInteger>FResult.ResFloat;
end;
if OK then
Case N.ResultType of
rtFloat: FResult.ResFloat:=N.ResFloat;
rtinteger: FResult.ResFloat:=N.ResInteger;
rtCurrency: FResult.ResCurrency:=N.ResCurrency;
end;
end;
{ TAggregateMin }
procedure TAggregateMin.InitAggregate;
begin
inherited InitAggregate;
FFirst:=True;
FResult.ResultType:=FArgumentNodes[0].NodeType;
Case FResult.ResultType of
rtFloat : FResult.resFloat:=0.0;
rtCurrency : FResult.resCurrency:=0.0;
rtInteger : FResult.resInteger:=0;
end;
end;
procedure TAggregateMin.UpdateAggregate;
Var
OK : Boolean;
N : TFPExpressionResult;
begin
FArgumentNodes[0].GetNodeValue(N);
if FFirst then
begin
FFirst:=False;
OK:=True;
end
else else
Case N.ResultType of Case N.ResultType of
rtFloat: OK:=N.ResFloat<FResult.ResFloat; rtFloat: OK:=N.ResFloat<FResult.ResFloat;
rtCurrency: OK:=N.ResCurrency<FResult.ResCurrency;
rtinteger: OK:=N.ResInteger<FResult.ResFloat; rtinteger: OK:=N.ResInteger<FResult.ResFloat;
end; end;
if OK then if OK then
Case FResult.ResultType of Case FResult.ResultType of
rtFloat: FResult.ResFloat:=N.ResFloat; rtFloat: FResult.ResFloat:=N.ResFloat;
rtCurrency: FResult.ResCurrency:=N.ResCurrency;
rtinteger: FResult.ResFloat:=N.ResInteger; rtinteger: FResult.ResFloat:=N.ResInteger;
end; end;
inherited UpdateAggregate; inherited UpdateAggregate;
@ -1007,7 +1102,6 @@ end;
procedure TAggregateAvg.InitAggregate; procedure TAggregateAvg.InitAggregate;
begin begin
inherited InitAggregate; inherited InitAggregate;
FCount:=0;
end; end;
procedure TAggregateAvg.UpdateAggregate; procedure TAggregateAvg.UpdateAggregate;
@ -1019,15 +1113,30 @@ end;
procedure TAggregateAvg.GetNodeValue(var Result: TFPExpressionResult); procedure TAggregateAvg.GetNodeValue(var Result: TFPExpressionResult);
begin begin
inherited GetNodeValue(Result); inherited GetNodeValue(Result);
Result.ResultType:=rtFloat; Result.ResultType:=FResult.ResultType;
if FCount=0 then if FCount=0 then
Result.ResFloat:=0 Case FResult.ResultType of
rtInteger:
begin
Result.ResultType:=rtFloat;
Result.ResFloat:=0.0;
end;
rtFloat:
Result.ResFloat:=0.0;
rtCurrency:
Result.ResCurrency:=0.0;
end
else else
Case FResult.ResultType of Case FResult.ResultType of
rtInteger: rtInteger:
begin
Result.ResultType:=rtFloat;
Result.ResFloat:=FResult.ResInteger/FCount; Result.ResFloat:=FResult.ResInteger/FCount;
end;
rtFloat: rtFloat:
Result.ResFloat:=FResult.ResFloat/FCount; Result.ResFloat:=FResult.ResFloat/FCount;
rtCurrency:
Result.ResCurrency:=FResult.ResCurrency/FCount;
end; end;
end; end;
@ -1058,12 +1167,20 @@ end;
{ TAggregateSum } { TAggregateSum }
function TAggregateSum.ConvertArgument(aIndex: Integer; aNode: TFPExprNode; aType: TResultType): TFPExprNode;
begin
if not (aNode.NodeType in [rtFloat,rtInteger,rtCurrency]) then
RaiseParserError(SErrInvalidArgumentType,[aIndex,ResultTypeName(aType),ResultTypeName(aNode.NodeType)]);
Result:=aNode;
end;
procedure TAggregateSum.InitAggregate; procedure TAggregateSum.InitAggregate;
begin begin
FResult.ResultType:=FArgumentNodes[0].NodeType; FResult.ResultType:=FArgumentNodes[0].NodeType;
Case FResult.ResultType of Case FResult.ResultType of
rtFloat: FResult.ResFloat:=0.0; rtFloat: FResult.ResFloat:=0.0;
rtCurrency : FResult.ResCurrency:=0.0;
rtinteger: FResult.ResInteger:=0; rtinteger: FResult.ResInteger:=0;
end; end;
end; end;
@ -1077,6 +1194,7 @@ begin
FArgumentNodes[0].GetNodeValue(R); FArgumentNodes[0].GetNodeValue(R);
Case FResult.ResultType of Case FResult.ResultType of
rtFloat: FResult.ResFloat:=FResult.ResFloat+R.ResFloat; rtFloat: FResult.ResFloat:=FResult.ResFloat+R.ResFloat;
rtCurrency: FResult.ResCurrency:=FResult.ResCurrency+R.ResCurrency;
rtinteger: FResult.ResInteger:=FResult.ResInteger+R.ResInteger; rtinteger: FResult.ResInteger:=FResult.ResInteger+R.ResInteger;
end; end;
end; end;
@ -1468,7 +1586,7 @@ begin
FIdentifiers.Assign(AValue) FIdentifiers.Assign(AValue)
end; end;
procedure TFPExpressionParser.EvaluateExpression(var Result: TFPExpressionResult); procedure TFPExpressionParser.EvaluateExpression(Out Result: TFPExpressionResult);
begin begin
If (FExpression='') then If (FExpression='') then
ParserError(SErrInExpressionEmpty); ParserError(SErrInExpressionEmpty);
@ -1493,19 +1611,26 @@ begin
Raise EExprParser.Create(Msg); Raise EExprParser.Create(Msg);
end; end;
function TFPExpressionParser.ConvertNode(Todo : TFPExprNode; ToType : TResultType): TFPExprNode; Class function TFPExpressionParser.ConvertNode(Todo : TFPExprNode; ToType : TResultType): TFPExprNode;
begin begin
Result:=ToDo; Result:=ToDo;
Case ToDo.NodeType of Case ToDo.NodeType of
rtInteger : rtInteger :
Case ToType of Case ToType of
rtFloat : Result:=TIntToFloatNode.Create(Result); rtFloat : Result:=TIntToFloatNode.Create(Result);
rtCurrency : Result:=TIntToCurrencyNode.Create(Result);
rtDateTime : Result:=TIntToDateTimeNode.Create(Result); rtDateTime : Result:=TIntToDateTimeNode.Create(Result);
end; end;
rtFloat : rtFloat :
Case ToType of Case ToType of
rtCurrency : Result:=TFloatToCurrencyNode.Create(Result);
rtDateTime : Result:=TFloatToDateTimeNode.Create(Result); rtDateTime : Result:=TFloatToDateTimeNode.Create(Result);
end; end;
rtCurrency :
Case ToType of
rtFloat : Result:=TCurrencyToFloatNode.Create(Result);
rtDateTime : Result:=TCurrencyToDateTimeNode.Create(Result);
end;
end; end;
end; end;
@ -1537,8 +1662,26 @@ var
begin begin
EvaluateExpression(Res); EvaluateExpression(Res);
CheckResultType(Res,rtFloat); CheckResultTypes(Res,[rtFloat,rtCurrency,rtInteger]);
Result:=Res.ResFloat; case Res.ResultType of
rtInteger : Result:=Res.ResInteger;
rtFloat : Result:=Res.ResFloat;
rtCurrency : Result:=res.ResCurrency;
end;
end;
function TFPExpressionParser.GetAsCurrency: Currency;
var
Res: TFPExpressionResult;
begin
EvaluateExpression(Res);
CheckResultTypes(Res,[rtFloat,rtCurrency,rtInteger]);
case Res.ResultType of
rtInteger : Result:=Res.ResInteger;
rtFloat : Result:=Res.ResFloat;
rtCurrency : Result:=res.ResCurrency;
end;
end; end;
function TFPExpressionParser.GetAsInteger: Int64; function TFPExpressionParser.GetAsInteger: Int64;
@ -1572,24 +1715,23 @@ end;
function TFPExpressionParser.MatchNodes(Todo,Match : TFPExprNode): TFPExprNode; function TFPExpressionParser.MatchNodes(Todo,Match : TFPExprNode): TFPExprNode;
Var Var
TT,MT : TResultType; FromType,ToType : TResultType;
begin begin
Result:=Todo; Result:=Todo;
TT:=Todo.NodeType; FromType:=Todo.NodeType;
MT:=Match.NodeType; ToType:=Match.NodeType;
If (TT<>MT) then If (FromType<>ToType) then
begin Case FromType of
if (TT=rtInteger) then rtInteger:
begin if (ToType in [rtFloat,rtCurrency,rtDateTime]) then
if (MT in [rtFloat,rtDateTime]) then Result:=ConvertNode(Todo,toType);
Result:=ConvertNode(Todo,MT); rtFloat:
end if (ToType in [rtCurrency,rtDateTime]) then
else if (TT=rtFloat) then Result:=ConvertNode(Todo,toType);
begin rtCurrency:
if (MT=rtDateTime) then if (ToType in [rtFloat,rtDateTime]) then
Result:=ConvertNode(Todo,rtDateTime); Result:=ConvertNode(Todo,toType);
end;
end; end;
end; end;
@ -1937,6 +2079,12 @@ begin
RaiseParserError(SErrInvalidResultType,[ResultTypeName(Res.ResultType)]); RaiseParserError(SErrInvalidResultType,[ResultTypeName(Res.ResultType)]);
end; end;
procedure TFPExpressionParser.CheckResultTypes(const Res: TFPExpressionResult; ATypes: TResultTypes);
begin
If Not (Res.ResultType in ATypes) then
RaiseParserError(SErrInvalidResultType,[ResultTypeName(Res.ResultType)]);
end;
class function TFPExpressionParser.BuiltinsManager: TExprBuiltInManager; class function TFPExpressionParser.BuiltinsManager: TExprBuiltInManager;
begin begin
Result:=BuiltinIdentifiers; Result:=BuiltinIdentifiers;
@ -2085,6 +2233,15 @@ begin
Result.FValue.ResFloat:=AValue; Result.FValue.ResFloat:=AValue;
end; end;
function TFPExprIdentifierDefs.AddCurrencyVariable(const AName: ShortString; AValue: Currency): TFPExprIdentifierDef;
begin
Result:=Add as TFPExprIdentifierDef;
Result.IdentifierType:=itVariable;
Result.Name:=AName;
Result.ResultType:=rtCurrency;
Result.FValue.ResCurrency:=AValue;
end;
function TFPExprIdentifierDefs.AddStringVariable(const AName: ShortString; function TFPExprIdentifierDefs.AddStringVariable(const AName: ShortString;
AValue: String): TFPExprIdentifierDef; AValue: String): TFPExprIdentifierDef;
begin begin
@ -2172,6 +2329,7 @@ begin
rtBoolean : FValue.ResBoolean:=FStringValue='True'; rtBoolean : FValue.ResBoolean:=FStringValue='True';
rtInteger : FValue.ResInteger:=StrToInt(AValue); rtInteger : FValue.ResInteger:=StrToInt(AValue);
rtFloat : FValue.ResFloat:=StrToFloat(AValue, FileFormatSettings); rtFloat : FValue.ResFloat:=StrToFloat(AValue, FileFormatSettings);
rtCurrency : FValue.ResFloat:=StrToCurr(AValue, FileFormatSettings);
rtDateTime : FValue.ResDateTime:=StrToDateTime(AValue, FileFormatSettings); rtDateTime : FValue.ResDateTime:=StrToDateTime(AValue, FileFormatSettings);
rtString : FValue.ResString:=AValue; rtString : FValue.ResString:=AValue;
end end
@ -2180,6 +2338,7 @@ begin
rtBoolean : FValue.ResBoolean:=False; rtBoolean : FValue.ResBoolean:=False;
rtInteger : FValue.ResInteger:=0; rtInteger : FValue.ResInteger:=0;
rtFloat : FValue.ResFloat:=0.0; rtFloat : FValue.ResFloat:=0.0;
rtCurrency : FValue.ResCurrency:=0.0;
rtDateTime : FValue.ResDateTime:=0; rtDateTime : FValue.ResDateTime:=0;
rtString : FValue.ResString:=''; rtString : FValue.ResString:='';
end end
@ -2260,6 +2419,13 @@ begin
FValue.ResFloat:=AValue; FValue.ResFloat:=AValue;
end; end;
procedure TFPExprIdentifierDef.SetAsCurrency(const AValue: Currency);
begin
CheckVariable;
CheckResultType(rtCurrency);
FValue.ResCurrency:=AValue;
end;
procedure TFPExprIdentifierDef.SetAsInteger(const AValue: Int64); procedure TFPExprIdentifierDef.SetAsInteger(const AValue: Int64);
begin begin
CheckVariable; CheckVariable;
@ -2283,6 +2449,7 @@ begin
Result:='False'; Result:='False';
rtInteger : Result:=IntToStr(FValue.ResInteger); rtInteger : Result:=IntToStr(FValue.ResInteger);
rtFloat : Result:=FloatToStr(FValue.ResFloat, FileFormatSettings); rtFloat : Result:=FloatToStr(FValue.ResFloat, FileFormatSettings);
rtCurrency : Result:=CurrToStr(FValue.ResCurrency, FileFormatSettings);
rtDateTime : Result:=FormatDateTime('cccc',FValue.ResDateTime, FileFormatSettings); rtDateTime : Result:=FormatDateTime('cccc',FValue.ResDateTime, FileFormatSettings);
rtString : Result:=FValue.ResString; rtString : Result:=FValue.ResString;
end; end;
@ -2304,7 +2471,7 @@ begin
if RT2<>RT then if RT2<>RT then
begin begin
// Automatically convert integer to float. // Automatically convert integer to float.
if (rt2=rtInteger) and (rt=rtFLoat) then if (rt2=rtInteger) and (rt=rtFloat) then
begin begin
FValue.ResultType:=RT; FValue.ResultType:=RT;
I:=FValue.resInteger; I:=FValue.resInteger;
@ -2340,6 +2507,13 @@ begin
Result:=FValue.ResFloat; Result:=FValue.ResFloat;
end; end;
function TFPExprIdentifierDef.GetAsCurrency: Currency;
begin
CheckResultType(rtCurrency);
CheckVariable;
Result:=FValue.ResCurrency;
end;
function TFPExprIdentifierDef.GetAsBoolean: Boolean; function TFPExprIdentifierDef.GetAsBoolean: Boolean;
begin begin
CheckResultType(rtBoolean); CheckResultType(rtBoolean);
@ -2445,6 +2619,13 @@ begin
Result.Category:=ACategory; Result.Category:=ACategory;
end; end;
function TExprBuiltInManager.AddCurrencyVariable(const ACategory: TBuiltInCategory; const AName: ShortString; AValue: Currency
): TFPBuiltInExprIdentifierDef;
begin
Result:=TFPBuiltInExprIdentifierDef(FDefs.AddCurrencyVariable(AName,AValue));
Result.Category:=ACategory;
end;
function TExprBuiltInManager.AddStringVariable( function TExprBuiltInManager.AddStringVariable(
const ACategory: TBuiltInCategory; const AName: ShortString; AValue: String const ACategory: TBuiltInCategory; const AName: ShortString; AValue: String
): TFPBuiltInExprIdentifierDef; ): TFPBuiltInExprIdentifierDef;
@ -2621,6 +2802,13 @@ begin
FValue.ResFloat:=AValue; FValue.ResFloat:=AValue;
end; end;
constructor TFPConstExpression.CreateCurrency(AValue: Currency);
begin
Inherited create;
FValue.ResultType:=rtCurrency;
FValue.ResCurrency:=AValue;
end;
constructor TFPConstExpression.CreateBoolean(AValue: Boolean); constructor TFPConstExpression.CreateBoolean(AValue: Boolean);
begin begin
FValue.ResultType:=rtBoolean; FValue.ResultType:=rtBoolean;
@ -2650,6 +2838,7 @@ begin
rtDateTime : Result:=''''+FormatDateTime('cccc',FValue.resDateTime)+''''; rtDateTime : Result:=''''+FormatDateTime('cccc',FValue.resDateTime)+'''';
rtBoolean : If FValue.ResBoolean then Result:='True' else Result:='False'; rtBoolean : If FValue.ResBoolean then Result:='True' else Result:='False';
rtFloat : Str(FValue.ResFloat,Result); rtFloat : Str(FValue.ResFloat,Result);
rtCurrency : Str(FValue.ResCurrency,Result);
end; end;
end; end;
@ -2659,7 +2848,7 @@ end;
procedure TFPNegateOperation.Check; procedure TFPNegateOperation.Check;
begin begin
Inherited; Inherited;
If Not (Operand.NodeType in [rtInteger,rtFloat]) then If Not (Operand.NodeType in [rtInteger,rtFloat,rtCurrency]) then
RaiseParserError(SErrNoNegation,[ResultTypeName(Operand.NodeType),Operand.AsString]) RaiseParserError(SErrNoNegation,[ResultTypeName(Operand.NodeType),Operand.AsString])
end; end;
@ -2674,6 +2863,7 @@ begin
Case Result.ResultType of Case Result.ResultType of
rtInteger : Result.resInteger:=-Result.ResInteger; rtInteger : Result.resInteger:=-Result.ResInteger;
rtFloat : Result.resFloat:=-Result.ResFloat; rtFloat : Result.resFloat:=-Result.ResFloat;
rtCurrency : Result.resCurrency:=-Result.ResCurrency;
end; end;
end; end;
@ -2917,7 +3107,8 @@ begin
Case RT.ResultType of Case RT.ResultType of
rtBoolean : B:=RT.ResBoolean=RV.ResBoolean; rtBoolean : B:=RT.ResBoolean=RV.ResBoolean;
rtInteger : B:=RT.ResInteger=RV.ResInteger; rtInteger : B:=RT.ResInteger=RV.ResInteger;
rtFloat : B:=RT.ResFloat=RV.ResFLoat; rtFloat : B:=RT.ResFloat=RV.ResFloat;
rtCurrency : B:=RT.resCurrency=RV.resCurrency;
rtDateTime : B:=RT.ResDateTime=RV.ResDateTime; rtDateTime : B:=RT.ResDateTime=RV.ResDateTime;
rtString : B:=RT.ResString=RV.ResString; rtString : B:=RT.ResString=RV.ResString;
end; end;
@ -3072,7 +3263,8 @@ begin
Case Result.ResultType of Case Result.ResultType of
rtBoolean : Result.resBoolean:=Result.ResBoolean=RRes.ResBoolean; rtBoolean : Result.resBoolean:=Result.ResBoolean=RRes.ResBoolean;
rtInteger : Result.resBoolean:=Result.ResInteger=RRes.ResInteger; rtInteger : Result.resBoolean:=Result.ResInteger=RRes.ResInteger;
rtFloat : Result.resBoolean:=Result.ResFloat=RRes.ResFLoat; rtFloat : Result.resBoolean:=Result.ResFloat=RRes.ResFloat;
rtCurrency : Result.resBoolean:=Result.resCurrency=RRes.resCurrency;
rtDateTime : Result.resBoolean:=Result.ResDateTime=RRes.ResDateTime; rtDateTime : Result.resBoolean:=Result.ResDateTime=RRes.ResDateTime;
rtString : Result.resBoolean:=Result.ResString=RRes.ResString; rtString : Result.resBoolean:=Result.ResString=RRes.ResString;
end; end;
@ -3109,7 +3301,8 @@ begin
Right.GetNodeValue(RRes); Right.GetNodeValue(RRes);
Case Result.ResultType of Case Result.ResultType of
rtInteger : Result.resBoolean:=Result.ResInteger<RRes.ResInteger; rtInteger : Result.resBoolean:=Result.ResInteger<RRes.ResInteger;
rtFloat : Result.resBoolean:=Result.ResFloat<RRes.ResFLoat; rtFloat : Result.resBoolean:=Result.ResFloat<RRes.ResFloat;
rtCurrency : Result.resBoolean:=Result.resCurrency<RRes.resCurrency;
rtDateTime : Result.resBoolean:=Result.ResDateTime<RRes.ResDateTime; rtDateTime : Result.resBoolean:=Result.ResDateTime<RRes.ResDateTime;
rtString : Result.resBoolean:=Result.ResString<RRes.ResString; rtString : Result.resBoolean:=Result.ResString<RRes.ResString;
end; end;
@ -3135,10 +3328,17 @@ begin
rtInteger : case Right.NodeType of rtInteger : case Right.NodeType of
rtInteger : Result.resBoolean:=Result.ResInteger>RRes.ResInteger; rtInteger : Result.resBoolean:=Result.ResInteger>RRes.ResInteger;
rtFloat : Result.resBoolean:=Result.ResInteger>RRes.ResFloat; rtFloat : Result.resBoolean:=Result.ResInteger>RRes.ResFloat;
rtCurrency : Result.resBoolean:=Result.ResInteger>RRes.resCurrency;
end; end;
rtFloat : case Right.NodeType of rtFloat : case Right.NodeType of
rtInteger : Result.resBoolean:=Result.ResFloat>RRes.ResInteger; rtInteger : Result.resBoolean:=Result.ResFloat>RRes.ResInteger;
rtFloat : Result.resBoolean:=Result.ResFloat>RRes.ResFLoat; rtFloat : Result.resBoolean:=Result.ResFloat>RRes.ResFloat;
rtCurrency : Result.resBoolean:=Result.ResFloat>RRes.ResCurrency;
end;
rtCurrency : case Right.NodeType of
rtInteger : Result.resBoolean:=Result.ResCurrency>RRes.ResInteger;
rtFloat : Result.resBoolean:=Result.ResCurrency>RRes.ResFloat;
rtCurrency : Result.resBoolean:=Result.ResCurrency>RRes.ResCurrency;
end; end;
rtDateTime : Result.resBoolean:=Result.ResDateTime>RRes.ResDateTime; rtDateTime : Result.resBoolean:=Result.ResDateTime>RRes.ResDateTime;
rtString : Result.resBoolean:=Result.ResString>RRes.ResString; rtString : Result.resBoolean:=Result.ResString>RRes.ResString;
@ -3177,7 +3377,7 @@ end;
procedure TFPOrderingOperation.Check; procedure TFPOrderingOperation.Check;
Const Const
AllowedTypes =[rtInteger,rtfloat,rtDateTime,rtString]; AllowedTypes =[rtInteger,rtfloat,rtCurrency,rtDateTime,rtString];
begin begin
CheckNodeType(Left,AllowedTypes); CheckNodeType(Left,AllowedTypes);
@ -3190,7 +3390,7 @@ end;
procedure TMathOperation.Check; procedure TMathOperation.Check;
Const Const
AllowedTypes =[rtInteger,rtfloat,rtDateTime,rtString]; AllowedTypes =[rtInteger,rtfloat,rtCurrency,rtDateTime,rtString];
begin begin
inherited Check; inherited Check;
@ -3223,7 +3423,8 @@ begin
rtInteger : Result.ResInteger:=Result.ResInteger+RRes.ResInteger; rtInteger : Result.ResInteger:=Result.ResInteger+RRes.ResInteger;
rtString : Result.ResString:=Result.ResString+RRes.ResString; rtString : Result.ResString:=Result.ResString+RRes.ResString;
rtDateTime : Result.ResDateTime:=Result.ResDateTime+RRes.ResDateTime; rtDateTime : Result.ResDateTime:=Result.ResDateTime+RRes.ResDateTime;
rtFloat : Result.ResFLoat:=Result.ResFLoat+RRes.ResFLoat; rtFloat : Result.ResFloat:=Result.ResFloat+RRes.ResFloat;
rtCurrency : Result.ResCurrency:=Result.ResCurrency+RRes.ResCurrency;
end; end;
Result.ResultType:=NodeType; Result.ResultType:=NodeType;
end; end;
@ -3233,7 +3434,7 @@ end;
procedure TFPSubtractOperation.check; procedure TFPSubtractOperation.check;
Const Const
AllowedTypes =[rtInteger,rtfloat,rtDateTime]; AllowedTypes =[rtInteger,rtfloat,rtCurrency,rtDateTime];
begin begin
CheckNodeType(Left,AllowedTypes); CheckNodeType(Left,AllowedTypes);
@ -3257,7 +3458,8 @@ begin
case Result.ResultType of case Result.ResultType of
rtInteger : Result.ResInteger:=Result.ResInteger-RRes.ResInteger; rtInteger : Result.ResInteger:=Result.ResInteger-RRes.ResInteger;
rtDateTime : Result.ResDateTime:=Result.ResDateTime-RRes.ResDateTime; rtDateTime : Result.ResDateTime:=Result.ResDateTime-RRes.ResDateTime;
rtFloat : Result.ResFLoat:=Result.ResFLoat-RRes.ResFLoat; rtFloat : Result.ResFloat:=Result.ResFloat-RRes.ResFloat;
rtCurrency : Result.resCurrency:=Result.resCurrency-RRes.ResCurrency;
end; end;
end; end;
@ -3266,7 +3468,7 @@ end;
procedure TFPMultiplyOperation.check; procedure TFPMultiplyOperation.check;
Const Const
AllowedTypes =[rtInteger,rtfloat]; AllowedTypes =[rtInteger,rtCurrency,rtfloat];
begin begin
CheckNodeType(Left,AllowedTypes); CheckNodeType(Left,AllowedTypes);
@ -3288,7 +3490,8 @@ begin
Right.GetNodeValue(RRes); Right.GetNodeValue(RRes);
case Result.ResultType of case Result.ResultType of
rtInteger : Result.ResInteger:=Result.ResInteger*RRes.ResInteger; rtInteger : Result.ResInteger:=Result.ResInteger*RRes.ResInteger;
rtFloat : Result.ResFLoat:=Result.ResFLoat*RRes.ResFLoat; rtFloat : Result.ResFloat:=Result.ResFloat*RRes.ResFloat;
rtCurrency : Result.ResCurrency:=Result.ResCurrency*RRes.ResCurrency;
end; end;
end; end;
@ -3296,7 +3499,7 @@ end;
procedure TFPDivideOperation.check; procedure TFPDivideOperation.check;
Const Const
AllowedTypes =[rtInteger,rtfloat]; AllowedTypes =[rtInteger,rtCurrency,rtfloat];
begin begin
CheckNodeType(Left,AllowedTypes); CheckNodeType(Left,AllowedTypes);
@ -3310,8 +3513,12 @@ begin
end; end;
function TFPDivideOperation.NodeType: TResultType; function TFPDivideOperation.NodeType: TResultType;
begin begin
Result:=rtFLoat; if (Left.NodeType=rtCurrency) and (Right.NodeType=rtCurrency) then
Result:=rtCurrency
else
Result:=rtFloat;
end; end;
Procedure TFPDivideOperation.GetNodeValue(var Result : TFPExpressionResult); Procedure TFPDivideOperation.GetNodeValue(var Result : TFPExpressionResult);
@ -3324,16 +3531,21 @@ begin
Right.GetNodeValue(RRes); Right.GetNodeValue(RRes);
case Result.ResultType of case Result.ResultType of
rtInteger : Result.ResFloat:=Result.ResInteger/RRes.ResInteger; rtInteger : Result.ResFloat:=Result.ResInteger/RRes.ResInteger;
rtFloat : Result.ResFLoat:=Result.ResFLoat/RRes.ResFLoat; rtFloat : Result.ResFloat:=Result.ResFloat/RRes.ResFloat;
rtCurrency :
if NodeType=rtCurrency then
Result.ResCurrency:=Result.ResCurrency/RRes.ResCurrency
else
Result.ResFloat:=Result.ResFloat/RRes.ResFloat;
end; end;
Result.ResultType:=rtFloat; Result.ResultType:=NodeType;
end; end;
{ TFPPowerOperation } { TFPPowerOperation }
procedure TFPPowerOperation.Check; procedure TFPPowerOperation.Check;
const const
AllowedTypes = [rtInteger, rtFloat]; AllowedTypes = [rtInteger, rtCurrency, rtFloat];
begin begin
CheckNodeType(Left, AllowedTypes); CheckNodeType(Left, AllowedTypes);
CheckNodeType(Right, AllowedTypes); CheckNodeType(Right, AllowedTypes);
@ -3440,6 +3652,46 @@ begin
Result.ResultType:=rtDateTime; Result.ResultType:=rtDateTime;
end; end;
{ TCurrencyToDateTimeNode }
procedure TCurrencyToDateTimeNode.Check;
begin
inherited Check;
CheckNodeType(Operand,[rtCurrency]);
end;
function TCurrencyToDateTimeNode.NodeType: TResultType;
begin
Result:=rtDateTime;
end;
Procedure TCurrencyToDateTimeNode.GetNodeValue(var Result : TFPExpressionResult);
begin
Operand.GetNodeValue(Result);
Result.ResDateTime:=Result.ResCurrency;
Result.ResultType:=rtDateTime;
end;
{ TCurrencyToFloatNode }
procedure TCurrencyToFloatNode.Check;
begin
inherited Check;
CheckNodeType(Operand,[rtCurrency]);
end;
function TCurrencyToFloatNode.NodeType: TResultType;
begin
Result:=rtFloat;
end;
Procedure TCurrencyToFloatNode.GetNodeValue(var Result : TFPExpressionResult);
begin
Operand.GetNodeValue(Result);
Result.ResFloat:=Result.ResCurrency;
Result.ResultType:=rtFloat;
end;
{ TFPExprIdentifierNode } { TFPExprIdentifierNode }
constructor TFPExprIdentifierNode.CreateIdentifier(AID: TFPExprIdentifierDef); constructor TFPExprIdentifierNode.CreateIdentifier(AID: TFPExprIdentifierDef);
@ -3489,6 +3741,20 @@ begin
end; end;
end; end;
Function TFPExprFunction.ConvertArgument(aIndex : Integer; aNode : TFPExprNode; aType : TResultType) : TFPExprNode;
Var
N : TFPExprNode;
begin
// Automatically convert integers to floats for float/currency parameters
N:=TFPExpressionParser.ConvertNode(aNode,aType);
if (aNode=N) then
// No conversion was performed, raise error
RaiseParserError(SErrInvalidArgumentType,[aIndex,ResultTypeName(aType),ResultTypeName(aNode.NodeType)]);
Result:=N;
end;
function TFPExprFunction.HasAggregate: Boolean; function TFPExprFunction.HasAggregate: Boolean;
var var
I: Integer; I: Integer;
@ -3515,22 +3781,13 @@ begin
begin begin
rtp:=CharToResultType(FID.ParameterTypes[i+1]); rtp:=CharToResultType(FID.ParameterTypes[i+1]);
rta:=FArgumentNodes[i].NodeType; rta:=FArgumentNodes[i].NodeType;
If (rtp<>rta) then begin If (rtp<>rta) then
FArgumentNodes[i]:=ConvertArgument(I+1,FArgumentNodes[i],rtp);
// Automatically convert integers to floats in functions that return
// a float
if (rta = rtInteger) and (rtp = rtFloat) then begin
FArgumentNodes[i] := TIntToFloatNode.Create(FArgumentNodes[i]);
exit;
end;
RaiseParserError(SErrInvalidArgumentType,[I+1,ResultTypeName(rtp),ResultTypeName(rta)])
end;
end; end;
end; end;
constructor TFPExprFunction.CreateFunction(AID: TFPExprIdentifierDef; constructor TFPExprFunction.CreateFunction(AID: TFPExprIdentifierDef; const Args: TExprArgumentArray);
const Args: TExprArgumentArray);
begin begin
Inherited CreateIdentifier(AID); Inherited CreateIdentifier(AID);
FArgumentNodes:=Args; FArgumentNodes:=Args;
@ -3637,6 +3894,8 @@ function ArgToFloat(Arg: TFPExpressionResult): TExprFloat;
begin begin
if Arg.ResultType = rtInteger then if Arg.ResultType = rtInteger then
result := Arg.resInteger result := Arg.resInteger
else if Arg.ResultType = rtCurrency then
result := Arg.resCurrency
else else
result := Arg.resFloat; result := Arg.resFloat;
end; end;

View File

@ -506,6 +506,7 @@ type
procedure DoEchoBoolean(var Result: TFPExpressionResult; Const Args: TExprParameterArray); procedure DoEchoBoolean(var Result: TFPExpressionResult; Const Args: TExprParameterArray);
procedure DoEchoDate(var Result: TFPExpressionResult; Const Args: TExprParameterArray); procedure DoEchoDate(var Result: TFPExpressionResult; Const Args: TExprParameterArray);
procedure DoEchoFloat(var Result: TFPExpressionResult; Const Args: TExprParameterArray); procedure DoEchoFloat(var Result: TFPExpressionResult; Const Args: TExprParameterArray);
procedure DoEchoCurrency(var Result: TFPExpressionResult; Const Args: TExprParameterArray);
procedure DoEchoInteger(var Result: TFPExpressionResult; Const Args: TExprParameterArray); procedure DoEchoInteger(var Result: TFPExpressionResult; Const Args: TExprParameterArray);
procedure DoEchoString(var Result: TFPExpressionResult; Const Args: TExprParameterArray); procedure DoEchoString(var Result: TFPExpressionResult; Const Args: TExprParameterArray);
procedure DoGetDate(var Result: TFPExpressionResult; Const Args: TExprParameterArray); procedure DoGetDate(var Result: TFPExpressionResult; Const Args: TExprParameterArray);
@ -518,6 +519,7 @@ type
Procedure AssertOperand(N : TFPExprNode; OperandClass : TClass); Procedure AssertOperand(N : TFPExprNode; OperandClass : TClass);
Procedure AssertResultType(RT : TResultType); Procedure AssertResultType(RT : TResultType);
Procedure AssertResult(F : TExprFloat); Procedure AssertResult(F : TExprFloat);
Procedure AssertCurrencyResult(C : Currency);
Procedure AssertResult(I : Int64); Procedure AssertResult(I : Int64);
Procedure AssertResult(S : String); Procedure AssertResult(S : String);
Procedure AssertResult(B : Boolean); Procedure AssertResult(B : Boolean);
@ -730,9 +732,10 @@ type
FTest33 : TFPExprIdentifierDef; FTest33 : TFPExprIdentifierDef;
procedure DoGetBooleanVar(var Res: TFPExpressionResult; ConstRef AName: ShortString); procedure DoGetBooleanVar(var Res: TFPExpressionResult; ConstRef AName: ShortString);
procedure DoGetBooleanVarWrong(var Res: TFPExpressionResult; ConstRef AName: ShortString); procedure DoGetBooleanVarWrong(var Res: TFPExpressionResult; ConstRef AName: ShortString);
procedure DoTestVariable33;
procedure TestAccess(Skip: TResultType); procedure TestAccess(Skip: TResultType);
procedure TestAccess(Skip: TResultTypes);
Protected Protected
procedure DoTestVariable33;
procedure AddVariabletwice; procedure AddVariabletwice;
procedure UnknownVariable; procedure UnknownVariable;
Procedure ReadWrongType; Procedure ReadWrongType;
@ -775,6 +778,8 @@ type
procedure TestVariable32; procedure TestVariable32;
procedure TestVariable33; procedure TestVariable33;
procedure TestVariable34; procedure TestVariable34;
procedure TestVariable35;
procedure TestVariable36;
end; end;
{ TTestParserFunctions } { TTestParserFunctions }
@ -814,6 +819,10 @@ type
procedure TestFunction27; procedure TestFunction27;
procedure TestFunction28; procedure TestFunction28;
procedure TestFunction29; procedure TestFunction29;
procedure TestFunction30;
procedure TestFunction31;
procedure TestFunction32;
procedure TestFunction33;
end; end;
{ TAggregateNode } { TAggregateNode }
@ -851,6 +860,7 @@ type
Procedure TestCountAggregate; Procedure TestCountAggregate;
Procedure TestSumAggregate; Procedure TestSumAggregate;
Procedure TestSumAggregate2; Procedure TestSumAggregate2;
Procedure TestSumAggregate3;
Procedure TestAvgAggregate; Procedure TestAvgAggregate;
Procedure TestAvgAggregate2; Procedure TestAvgAggregate2;
Procedure TestAvgAggregate3; Procedure TestAvgAggregate3;
@ -871,6 +881,7 @@ type
procedure TestVariable4; procedure TestVariable4;
procedure TestVariable5; procedure TestVariable5;
procedure TestVariable6; procedure TestVariable6;
procedure TestVariable7;
procedure TestFunction1; procedure TestFunction1;
procedure TestFunction2; procedure TestFunction2;
end; end;
@ -895,6 +906,7 @@ type
procedure AssertDateTimeExpression(Const AExpression : String; Const AResult : TDateTime); procedure AssertDateTimeExpression(Const AExpression : String; Const AResult : TDateTime);
procedure AssertAggregateExpression(Const AExpression : String; AResult : Int64; AUpdateCount : integer); procedure AssertAggregateExpression(Const AExpression : String; AResult : Int64; AUpdateCount : integer);
procedure AssertAggregateExpression(Const AExpression : String; AResult : TExprFloat; AUpdateCount : integer); procedure AssertAggregateExpression(Const AExpression : String; AResult : TExprFloat; AUpdateCount : integer);
procedure AssertAggregateCurrExpression(Const AExpression : String; AResult : Currency; AUpdateCount : integer);
Published Published
procedure TestRegister; procedure TestRegister;
Procedure TestVariablepi; Procedure TestVariablepi;
@ -962,6 +974,8 @@ type
Procedure TestFunctionstrtodatetime; Procedure TestFunctionstrtodatetime;
Procedure TestFunctionstrtodatetimedef; Procedure TestFunctionstrtodatetimedef;
Procedure TestFunctionAggregateSum; Procedure TestFunctionAggregateSum;
Procedure TestFunctionAggregateSumFloat;
Procedure TestFunctionAggregateSumCurrency;
Procedure TestFunctionAggregateCount; Procedure TestFunctionAggregateCount;
Procedure TestFunctionAggregateAvg; Procedure TestFunctionAggregateAvg;
Procedure TestFunctionAggregateMin; Procedure TestFunctionAggregateMin;
@ -1004,6 +1018,7 @@ begin
Case Result.ResultType of Case Result.ResultType of
rtInteger : Result.ResInteger:=FVarValue; rtInteger : Result.ResInteger:=FVarValue;
rtFloat : Result.ResFloat:=FVarValue / 2; rtFloat : Result.ResFloat:=FVarValue / 2;
rtCurrency : Result.ResCurrency:=FVarValue / 2;
end; end;
end; end;
@ -1163,6 +1178,40 @@ begin
end; end;
end; end;
procedure TTestParserAggregate.TestSumAggregate3;
Var
C : TAggregateSum;
V : TFPExprVariable;
I : Integer;
R : TFPExpressionResult;
A : TExprArgumentArray;
begin
FFunction.ResultType:=rtCurrency;
FFunction.ParameterTypes:='F';
FFunction.Name:='SUM';
FFunction2.ResultType:=rtCurrency;
C:=Nil;
V:=TFPExprVariable.CreateIdentifier(FFunction2);
try
SetLength(A,1);
A[0]:=V;
C:=TAggregateSum.CreateFunction(FFunction,A);
C.Check;
C.InitAggregate;
For I:=1 to 10 do
begin
FVarValue:=I;
C.UpdateAggregate;
end;
C.GetNodeValue(R);
AssertEquals('Correct type',rtCurrency,R.ResultType);
AssertEquals('Correct value',55/2,R.ResCurrency,0.1);
finally
C.Free;
end;
end;
procedure TTestParserAggregate.TestAvgAggregate; procedure TTestParserAggregate.TestAvgAggregate;
Var Var
@ -1237,7 +1286,6 @@ procedure TTestParserAggregate.TestAvgAggregate3;
Var Var
C : TAggregateAvg; C : TAggregateAvg;
V : TFPExprVariable; V : TFPExprVariable;
I : Integer;
R : TFPExpressionResult; R : TFPExpressionResult;
A : TExprArgumentArray; A : TExprArgumentArray;
@ -1565,6 +1613,7 @@ begin
AssertEquals('Correct result',2.34,FN.ConstValue.ResFloat); AssertEquals('Correct result',2.34,FN.ConstValue.ResFloat);
AssertEquals('Correct result',2.34,FN.NodeValue.ResFloat); AssertEquals('Correct result',2.34,FN.NodeValue.ResFloat);
Val(FN.AsString,F,C); Val(FN.AsString,F,C);
AssertEquals('Correct conversion',0,C);
AssertEquals('AsString ok',2.34,F,0.001); AssertEquals('AsString ok',2.34,F,0.001);
end; end;
@ -2828,6 +2877,12 @@ begin
AssertEquals('Correct float result',F,FP.Evaluate.ResFloat); AssertEquals('Correct float result',F,FP.Evaluate.ResFloat);
end; end;
procedure TTestExpressionParser.AssertCurrencyResult(C: Currency);
begin
AssertEquals('Correct currency result',C,FP.ExprNode.NodeValue.ResCurrency);
AssertEquals('Correct currency result',C,FP.Evaluate.ResCurrency);
end;
procedure TTestExpressionParser.AssertResult(I: Int64); procedure TTestExpressionParser.AssertResult(I: Int64);
begin begin
AssertEquals('Correct integer result',I,FP.ExprNode.NodeValue.ResInteger); AssertEquals('Correct integer result',I,FP.ExprNode.NodeValue.ResInteger);
@ -4439,6 +4494,7 @@ begin
rtString : res.ResString:=FP.Identifiers[0].AsString; rtString : res.ResString:=FP.Identifiers[0].AsString;
rtInteger : Res.ResInteger:=FP.Identifiers[0].AsInteger; rtInteger : Res.ResInteger:=FP.Identifiers[0].AsInteger;
rtFloat : Res.ResFloat:=FP.Identifiers[0].AsFloat; rtFloat : Res.ResFloat:=FP.Identifiers[0].AsFloat;
rtCurrency : Res.ResCurrency:=FP.Identifiers[0].AsCurrency;
rtDateTime : Res.ResDateTime:=FP.Identifiers[0].AsDateTime; rtDateTime : Res.ResDateTime:=FP.Identifiers[0].AsDateTime;
end; end;
end; end;
@ -4455,6 +4511,7 @@ begin
rtString : FP.Identifiers[0].AsString:=res.ResString; rtString : FP.Identifiers[0].AsString:=res.ResString;
rtInteger : FP.Identifiers[0].AsInteger:=Res.ResInteger; rtInteger : FP.Identifiers[0].AsInteger:=Res.ResInteger;
rtFloat : FP.Identifiers[0].AsFloat:=Res.ResFloat; rtFloat : FP.Identifiers[0].AsFloat:=Res.ResFloat;
rtCurrency : FP.Identifiers[0].AsCurrency:=Res.ResCurrency;
rtDateTime : FP.Identifiers[0].AsDateTime:=Res.ResDateTime; rtDateTime : FP.Identifiers[0].AsDateTime:=Res.ResDateTime;
end; end;
end; end;
@ -4540,14 +4597,12 @@ Var
begin begin
D:=Now; D:=Now;
I:=FP.Identifiers.AddDateTimeVariable('a',D); I:=FP.Identifiers.AddDateTimeVariable('a',D);
AssertNotNull('Addvariable returns result',I);
AssertException('Cannot add same name twice',EExprParser,@AddVariabletwice); AssertException('Cannot add same name twice',EExprParser,@AddVariabletwice);
end; end;
procedure TTestParserVariables.TestVariable8; procedure TTestParserVariables.TestVariable8;
Var
I : TFPExprIdentifierDef;
begin begin
FP.Identifiers.AddIntegerVariable('a',123); FP.Identifiers.AddIntegerVariable('a',123);
FP.Identifiers.AddIntegerVariable('b',123); FP.Identifiers.AddIntegerVariable('b',123);
@ -4564,6 +4619,7 @@ Var
begin begin
I:=FP.Identifiers.AddIntegerVariable('a',123); I:=FP.Identifiers.AddIntegerVariable('a',123);
AssertNotNull('Addvariable returns result',I);
FP.Expression:='a'; FP.Expression:='a';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPExprVariable, FP.ExprNode); AssertNodeType('Constant expression',TFPExprVariable, FP.ExprNode);
@ -4578,6 +4634,7 @@ Var
begin begin
I:=FP.Identifiers.AddStringVariable('a','a123'); I:=FP.Identifiers.AddStringVariable('a','a123');
AssertNotNull('Addvariable returns result',I);
FP.Expression:='a'; FP.Expression:='a';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPExprVariable, FP.ExprNode); AssertNodeType('Constant expression',TFPExprVariable, FP.ExprNode);
@ -4592,6 +4649,7 @@ Var
begin begin
I:=FP.Identifiers.AddFloatVariable('a',1.23); I:=FP.Identifiers.AddFloatVariable('a',1.23);
AssertNotNull('Addvariable returns result',I);
FP.Expression:='a'; FP.Expression:='a';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPExprVariable, FP.ExprNode); AssertNodeType('Constant expression',TFPExprVariable, FP.ExprNode);
@ -4599,6 +4657,21 @@ begin
AssertResult(1.23); AssertResult(1.23);
end; end;
procedure TTestParserVariables.TestVariable36;
Var
I : TFPExprIdentifierDef;
begin
I:=FP.Identifiers.AddCurrencyVariable('a',1.23);
AssertNotNull('Addvariable returns result',I);
FP.Expression:='a';
AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPExprVariable, FP.ExprNode);
AssertResultType(rtCurrency);
AssertCurrencyResult(1.23);
end;
procedure TTestParserVariables.TestVariable12; procedure TTestParserVariables.TestVariable12;
Var Var
@ -4606,6 +4679,7 @@ Var
begin begin
I:=FP.Identifiers.AddBooleanVariable('a',True); I:=FP.Identifiers.AddBooleanVariable('a',True);
AssertNotNull('Addvariable returns result',I);
FP.Expression:='a'; FP.Expression:='a';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPExprVariable, FP.ExprNode); AssertNodeType('Constant expression',TFPExprVariable, FP.ExprNode);
@ -4622,6 +4696,7 @@ Var
begin begin
D:=Date; D:=Date;
I:=FP.Identifiers.AddDateTimeVariable('a',D); I:=FP.Identifiers.AddDateTimeVariable('a',D);
AssertNotNull('Addvariable returns result',I);
FP.Expression:='a'; FP.Expression:='a';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPExprVariable, FP.ExprNode); AssertNodeType('Constant expression',TFPExprVariable, FP.ExprNode);
@ -4648,6 +4723,7 @@ Var
begin begin
I:=FP.Identifiers.AddIntegerVariable('a',1); I:=FP.Identifiers.AddIntegerVariable('a',1);
AssertNotNull('Addvariable returns result',I);
FP.BuildHashList; FP.BuildHashList;
S:=FP.IdentifierByName('A'); S:=FP.IdentifierByName('A');
AssertSame('Identifier found',I,S); AssertSame('Identifier found',I,S);
@ -4660,6 +4736,7 @@ Var
begin begin
I:=FP.Identifiers.AddIntegerVariable('a',1); I:=FP.Identifiers.AddIntegerVariable('a',1);
AssertNotNull('Addvariable returns result',I);
FP.BuildHashList; FP.BuildHashList;
S:=FP.IdentifierByName('B'); S:=FP.IdentifierByName('B');
AssertNull('Identifier not found',S); AssertNull('Identifier not found',S);
@ -4668,10 +4745,11 @@ end;
procedure TTestParserVariables.TestVariable17; procedure TTestParserVariables.TestVariable17;
Var Var
I,S : TFPExprIdentifierDef; I : TFPExprIdentifierDef;
begin begin
I:=FP.Identifiers.AddIntegerVariable('a',1); I:=FP.Identifiers.AddIntegerVariable('a',1);
AssertNotNull('Addvariable returns result',I);
FP.BuildHashList; FP.BuildHashList;
AssertException('Identifier not found',EExprParser,@unknownvariable); AssertException('Identifier not found',EExprParser,@unknownvariable);
end; end;
@ -4683,6 +4761,7 @@ Var
begin begin
I:=FP.Identifiers.AddIntegerVariable('a',1); I:=FP.Identifiers.AddIntegerVariable('a',1);
AssertNotNull('Addvariable returns result',I);
S:=FP.Identifiers.FindIdentifier('B'); S:=FP.Identifiers.FindIdentifier('B');
AssertNull('Identifier not found',S); AssertNull('Identifier not found',S);
end; end;
@ -4711,18 +4790,24 @@ end;
procedure TTestParserVariables.TestAccess(Skip : TResultType); procedure TTestParserVariables.TestAccess(Skip : TResultType);
begin
TestAccess([Skip]);
end;
procedure TTestParserVariables.TestAccess(Skip : TResultTypes);
Var Var
rt : TResultType; rt : TResultType;
begin begin
For rt:=Low(TResultType) to High(TResultType) do For rt:=Low(TResultType) to High(TResultType) do
if rt<>skip then if Not (rt in skip) then
begin begin
FasWrongType:=rt; FasWrongType:=rt;
AssertException('Acces as '+ResultTypeName(rt),EExprParser,@ReadWrongtype); AssertException('Acces as '+ResultTypeName(rt),EExprParser,@ReadWrongtype);
end; end;
For rt:=Low(TResultType) to High(TResultType) do For rt:=Low(TResultType) to High(TResultType) do
if rt<>skip then if Not (rt in skip) then
begin begin
FasWrongType:=rt; FasWrongType:=rt;
AssertException('Acces as '+ResultTypeName(rt),EExprParser,@WriteWrongtype); AssertException('Acces as '+ResultTypeName(rt),EExprParser,@WriteWrongtype);
@ -4732,13 +4817,20 @@ end;
procedure TTestParserVariables.TestVariable21; procedure TTestParserVariables.TestVariable21;
begin begin
FP.IDentifiers.AddIntegerVariable('a',1); FP.IDentifiers.AddIntegerVariable('a',1);
TestAccess(rtInteger); TestAccess([rtInteger]);
end; end;
procedure TTestParserVariables.TestVariable22; procedure TTestParserVariables.TestVariable22;
begin begin
FP.IDentifiers.AddFloatVariable('a',1.0); FP.IDentifiers.AddFloatVariable('a',1.0);
TestAccess(rtFloat); TestAccess([rtFloat]);
end;
procedure TTestParserVariables.TestVariable35;
begin
FP.IDentifiers.AddCurrencyVariable('a',1.0);
TestAccess([rtCurrency]);
end; end;
procedure TTestParserVariables.TestVariable23; procedure TTestParserVariables.TestVariable23;
@ -4886,6 +4978,7 @@ Var
begin begin
B:=FTest33.AsBoolean; B:=FTest33.AsBoolean;
AssertTrue(B in [true,False])
end; end;
procedure TTestParserVariables.TestVariable33; procedure TTestParserVariables.TestVariable33;
@ -4947,6 +5040,12 @@ begin
Result.resFloat:=Args[0].resFloat; Result.resFloat:=Args[0].resFloat;
end; end;
Procedure EchoCurrency(Var Result : TFPExpressionResult; Const Args : TExprParameterArray);
begin
Result.resCurrency:=Args[0].resCurrency;
end;
Procedure EchoString(Var Result : TFPExpressionResult; Const Args : TExprParameterArray); Procedure EchoString(Var Result : TFPExpressionResult; Const Args : TExprParameterArray);
begin begin
@ -4977,6 +5076,12 @@ begin
Result.resFloat:=Args[0].resFloat; Result.resFloat:=Args[0].resFloat;
end; end;
Procedure TTestExpressionParser.DoEchoCurrency(Var Result : TFPExpressionResult; Const Args : TExprParameterArray);
begin
Result.resCurrency:=Args[0].resCurrency;
end;
Procedure TTestExpressionParser.DoEchoString(Var Result : TFPExpressionResult; Const Args : TExprParameterArray); Procedure TTestExpressionParser.DoEchoString(Var Result : TFPExpressionResult; Const Args : TExprParameterArray);
begin begin
@ -5011,6 +5116,7 @@ begin
rtString : res.ResString:=FP.Identifiers[0].AsString; rtString : res.ResString:=FP.Identifiers[0].AsString;
rtInteger : Res.ResInteger:=FP.Identifiers[0].AsInteger; rtInteger : Res.ResInteger:=FP.Identifiers[0].AsInteger;
rtFloat : Res.ResFloat:=FP.Identifiers[0].AsFloat; rtFloat : Res.ResFloat:=FP.Identifiers[0].AsFloat;
rtCurrency : Res.ResCurrency:=FP.Identifiers[0].AsCurrency;
rtDateTime : Res.ResDateTime:=FP.Identifiers[0].AsDateTime; rtDateTime : Res.ResDateTime:=FP.Identifiers[0].AsDateTime;
end; end;
end; end;
@ -5027,6 +5133,7 @@ begin
rtString : FP.Identifiers[0].AsString:=res.ResString; rtString : FP.Identifiers[0].AsString:=res.ResString;
rtInteger : FP.Identifiers[0].AsInteger:=Res.ResInteger; rtInteger : FP.Identifiers[0].AsInteger:=Res.ResInteger;
rtFloat : FP.Identifiers[0].AsFloat:=Res.ResFloat; rtFloat : FP.Identifiers[0].AsFloat:=Res.ResFloat;
rtCurrency : FP.Identifiers[0].AsCurrency:=Res.ResCurrency;
rtDateTime : FP.Identifiers[0].AsDateTime:=Res.ResDateTime; rtDateTime : FP.Identifiers[0].AsDateTime:=Res.ResDateTime;
end; end;
end; end;
@ -5119,6 +5226,24 @@ begin
AssertException('No write access',EExprParser,@TryWrite); AssertException('No write access',EExprParser,@TryWrite);
end; end;
procedure TTestParserFunctions.TestFunction30;
Var
I : TFPExprIdentifierDef;
begin
I:=FP.Identifiers.AddFunction('EchoCurrency','C','C',@EchoCurrency);
AssertEquals('List is dirty',True,FP.Dirty);
AssertNotNull('Addvariable returns result',I);
AssertEquals('One variable added',1,FP.Identifiers.Count);
AssertSame('Result equals variable added',I,FP.Identifiers[0]);
AssertEquals('Function has correct resulttype',rtCurrency,I.ResultType);
AssertSame('Function has correct address',Pointer(@EchoCurrency),Pointer(I.OnGetFunctionValueCallBack));
FaccessAs:=rtCurrency;
AssertException('No read access',EExprParser,@TryRead);
AssertException('No write access',EExprParser,@TryWrite);
end;
procedure TTestParserFunctions.TestFunction6; procedure TTestParserFunctions.TestFunction6;
Var Var
@ -5197,6 +5322,21 @@ begin
// AssertSame('Function has correct address',Pointer(@EchoFloat),Pointer(I.OnGetFunctionValueCallBack)); // AssertSame('Function has correct address',Pointer(@EchoFloat),Pointer(I.OnGetFunctionValueCallBack));
end; end;
procedure TTestParserFunctions.TestFunction31;
Var
I : TFPExprIdentifierDef;
begin
I:=FP.Identifiers.AddFunction('EchoCurrency','C','C',@DoEchoCurrency);
AssertEquals('List is dirty',True,FP.Dirty);
AssertNotNull('Addvariable returns result',I);
AssertEquals('One variable added',1,FP.Identifiers.Count);
AssertSame('Result equals variable added',I,FP.Identifiers[0]);
AssertEquals('Function has correct resulttype',rtCurrency,I.ResultType);
// AssertSame('Function has correct address',Pointer(@EchoFloat),Pointer(I.OnGetFunctionValueCallBack));
end;
procedure TTestParserFunctions.TestFunction11; procedure TTestParserFunctions.TestFunction11;
Var Var
@ -5221,6 +5361,7 @@ Var
begin begin
D:=Date; D:=Date;
I:=FP.Identifiers.AddFunction('Date','D','',@GetDate); I:=FP.Identifiers.AddFunction('Date','D','',@GetDate);
AssertNotNull('Addvariable returns result',I);
FP.Expression:='Date'; FP.Expression:='Date';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPFunctionCallBack, FP.ExprNode); AssertNodeType('Constant expression',TFPFunctionCallBack, FP.ExprNode);
@ -5237,7 +5378,9 @@ Var
begin begin
D:=Date; D:=Date;
I:=FP.Identifiers.AddDateTimeVariable('a',D); I:=FP.Identifiers.AddDateTimeVariable('a',D);
AssertNotNull('Addvariable returns result',I);
I:=FP.Identifiers.AddFunction('EchoDate','D','D',@EchoDate); I:=FP.Identifiers.AddFunction('EchoDate','D','D',@EchoDate);
AssertNotNull('Addvariable returns result',I);
FP.Expression:='EchoDate(a)'; FP.Expression:='EchoDate(a)';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPFunctionCallBack, FP.ExprNode); AssertNodeType('Constant expression',TFPFunctionCallBack, FP.ExprNode);
@ -5248,11 +5391,10 @@ end;
procedure TTestParserFunctions.TestFunction14; procedure TTestParserFunctions.TestFunction14;
Var Var
I : TFPExprIdentifierDef; I : TFPExprIdentifierDef;
D : TDateTime;
begin begin
D:=Date;
I:=FP.Identifiers.AddFunction('EchoInteger','I','I',@EchoInteger); I:=FP.Identifiers.AddFunction('EchoInteger','I','I',@EchoInteger);
AssertNotNull('Addvariable returns result',I);
FP.Expression:='EchoInteger(13)'; FP.Expression:='EchoInteger(13)';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPFunctionCallBack, FP.ExprNode); AssertNodeType('Constant expression',TFPFunctionCallBack, FP.ExprNode);
@ -5263,11 +5405,10 @@ end;
procedure TTestParserFunctions.TestFunction15; procedure TTestParserFunctions.TestFunction15;
Var Var
I : TFPExprIdentifierDef; I : TFPExprIdentifierDef;
D : TDateTime;
begin begin
D:=Date;
I:=FP.Identifiers.AddFunction('EchoBoolean','B','B',@EchoBoolean); I:=FP.Identifiers.AddFunction('EchoBoolean','B','B',@EchoBoolean);
AssertNotNull('Addvariable returns result',I);
FP.Expression:='EchoBoolean(True)'; FP.Expression:='EchoBoolean(True)';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPFunctionCallBack, FP.ExprNode); AssertNodeType('Constant expression',TFPFunctionCallBack, FP.ExprNode);
@ -5278,11 +5419,10 @@ end;
procedure TTestParserFunctions.TestFunction16; procedure TTestParserFunctions.TestFunction16;
Var Var
I : TFPExprIdentifierDef; I : TFPExprIdentifierDef;
D : TDateTime;
begin begin
D:=Date;
I:=FP.Identifiers.AddFunction('EchoFloat','F','F',@EchoFloat); I:=FP.Identifiers.AddFunction('EchoFloat','F','F',@EchoFloat);
AssertNotNull('Have identifier',I);
FP.Expression:='EchoFloat(1.234)'; FP.Expression:='EchoFloat(1.234)';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPFunctionCallBack, FP.ExprNode); AssertNodeType('Constant expression',TFPFunctionCallBack, FP.ExprNode);
@ -5290,14 +5430,47 @@ begin
AssertResult(1.234); AssertResult(1.234);
end; end;
procedure TTestParserFunctions.TestFunction17; procedure TTestParserFunctions.TestFunction32;
Var
I : TFPExprIdentifierDef;
begin
// Note there will be an implicit conversion float-> currency as the const will be a float
I:=FP.Identifiers.AddFunction('EchoCurrency','C','C',@EchoCurrency);
AssertNotNull('Have identifier',I);
FP.Expression:='EchoCurrency(1.234)';
AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPFunctionCallBack, FP.ExprNode);
AssertResultType(rtCurrency);
AssertCurrencyResult(1.234);
end;
procedure TTestParserFunctions.TestFunction33;
Var
I : TFPExprIdentifierDef;
begin
// Note there will be no conversion
I:=FP.Identifiers.AddCurrencyVariable('a',1.234);
AssertNotNull('Have identifier',I);
I:=FP.Identifiers.AddFunction('EchoCurrency','C','C',@EchoCurrency);
AssertNotNull('Have identifier',I);
FP.Expression:='EchoCurrency(a)';
AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPFunctionCallBack, FP.ExprNode);
AssertResultType(rtCurrency);
AssertCurrencyResult(1.234);
end;
procedure TTestParserFunctions.TestFunction17;
Var Var
I : TFPExprIdentifierDef; I : TFPExprIdentifierDef;
D : TDateTime;
begin begin
D:=Date;
I:=FP.Identifiers.AddFunction('EchoString','S','S',@EchoString); I:=FP.Identifiers.AddFunction('EchoString','S','S',@EchoString);
AssertNotNull('Have identifier',I);
FP.Expression:='EchoString(''Aloha'')'; FP.Expression:='EchoString(''Aloha'')';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPFunctionCallBack, FP.ExprNode); AssertNodeType('Constant expression',TFPFunctionCallBack, FP.ExprNode);
@ -5315,7 +5488,9 @@ Var
begin begin
D:=Date; D:=Date;
I:=FP.Identifiers.AddDateTimeVariable('a',D); I:=FP.Identifiers.AddDateTimeVariable('a',D);
AssertNotNull('Have identifier',I);
I:=FP.Identifiers.AddFunction('EchoDate','D','D',@DoEchoDate); I:=FP.Identifiers.AddFunction('EchoDate','D','D',@DoEchoDate);
AssertNotNull('Have identifier',I);
FP.Expression:='EchoDate(a)'; FP.Expression:='EchoDate(a)';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPFunctionEventHandler, FP.ExprNode); AssertNodeType('Constant expression',TFPFunctionEventHandler, FP.ExprNode);
@ -5326,11 +5501,10 @@ end;
procedure TTestParserFunctions.TestFunction19; procedure TTestParserFunctions.TestFunction19;
Var Var
I : TFPExprIdentifierDef; I : TFPExprIdentifierDef;
D : TDateTime;
begin begin
D:=Date;
I:=FP.Identifiers.AddFunction('EchoInteger','I','I',@DoEchoInteger); I:=FP.Identifiers.AddFunction('EchoInteger','I','I',@DoEchoInteger);
AssertNotNull('Have identifier',I);
FP.Expression:='EchoInteger(13)'; FP.Expression:='EchoInteger(13)';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPFunctionEventHandler, FP.ExprNode); AssertNodeType('Constant expression',TFPFunctionEventHandler, FP.ExprNode);
@ -5341,11 +5515,10 @@ end;
procedure TTestParserFunctions.TestFunction20; procedure TTestParserFunctions.TestFunction20;
Var Var
I : TFPExprIdentifierDef; I : TFPExprIdentifierDef;
D : TDateTime;
begin begin
D:=Date;
I:=FP.Identifiers.AddFunction('EchoBoolean','B','B',@DoEchoBoolean); I:=FP.Identifiers.AddFunction('EchoBoolean','B','B',@DoEchoBoolean);
AssertNotNull('Have identifier',I);
FP.Expression:='EchoBoolean(True)'; FP.Expression:='EchoBoolean(True)';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPFunctionEventHandler, FP.ExprNode); AssertNodeType('Constant expression',TFPFunctionEventHandler, FP.ExprNode);
@ -5356,11 +5529,10 @@ end;
procedure TTestParserFunctions.TestFunction21; procedure TTestParserFunctions.TestFunction21;
Var Var
I : TFPExprIdentifierDef; I : TFPExprIdentifierDef;
D : TDateTime;
begin begin
D:=Date;
I:=FP.Identifiers.AddFunction('EchoFloat','F','F',@DoEchoFloat); I:=FP.Identifiers.AddFunction('EchoFloat','F','F',@DoEchoFloat);
AssertNotNull('Have identifier',I);
FP.Expression:='EchoFloat(1.234)'; FP.Expression:='EchoFloat(1.234)';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPFunctionEventHandler, FP.ExprNode); AssertNodeType('Constant expression',TFPFunctionEventHandler, FP.ExprNode);
@ -5371,11 +5543,10 @@ end;
procedure TTestParserFunctions.TestFunction22; procedure TTestParserFunctions.TestFunction22;
Var Var
I : TFPExprIdentifierDef; I : TFPExprIdentifierDef;
D : TDateTime;
begin begin
D:=Date;
I:=FP.Identifiers.AddFunction('EchoString','S','S',@DoEchoString); I:=FP.Identifiers.AddFunction('EchoString','S','S',@DoEchoString);
AssertNotNull('Have identifier',I);
FP.Expression:='EchoString(''Aloha'')'; FP.Expression:='EchoString(''Aloha'')';
AssertNotNull('Have result node',FP.ExprNode); AssertNotNull('Have result node',FP.ExprNode);
AssertNodeType('Constant expression',TFPFunctionEventHandler, FP.ExprNode); AssertNodeType('Constant expression',TFPFunctionEventHandler, FP.ExprNode);
@ -5392,6 +5563,7 @@ Var
begin begin
D:=Date; D:=Date;
I:=FP.Identifiers.AddFunction('Date','D','',@DoGetDate); I:=FP.Identifiers.AddFunction('Date','D','',@DoGetDate);
AssertNotNull('Have identifier',I);
AssertEquals('List is dirty',True,FP.Dirty); AssertEquals('List is dirty',True,FP.Dirty);
AssertNotNull('Addvariable returns result',I); AssertNotNull('Addvariable returns result',I);
AssertEquals('One variable added',1,FP.Identifiers.Count); AssertEquals('One variable added',1,FP.Identifiers.Count);
@ -5411,8 +5583,8 @@ Var
begin begin
I:=FP.Identifiers.AddFunction('AddInteger','I','II',@DoAddInteger); I:=FP.Identifiers.AddFunction('AddInteger','I','II',@DoAddInteger);
AssertNotNull('Have identifier',I);
AssertEquals('List is dirty',True,FP.Dirty); AssertEquals('List is dirty',True,FP.Dirty);
AssertNotNull('Addvariable returns result',I);
AssertEquals('One variable added',1,FP.Identifiers.Count); AssertEquals('One variable added',1,FP.Identifiers.Count);
AssertSame('Result equals variable added',I,FP.Identifiers[0]); AssertSame('Result equals variable added',I,FP.Identifiers[0]);
AssertEquals('Function has correct resulttype',rtInteger,I.ResultType); AssertEquals('Function has correct resulttype',rtInteger,I.ResultType);
@ -5431,7 +5603,7 @@ Var
begin begin
I:=FP.Identifiers.AddFunction('Delete','S','SII',@DoDeleteString); I:=FP.Identifiers.AddFunction('Delete','S','SII',@DoDeleteString);
AssertEquals('List is dirty',True,FP.Dirty); AssertEquals('List is dirty',True,FP.Dirty);
AssertNotNull('Addvariable returns result',I); AssertNotNull('Have identifier',I);
AssertEquals('One variable added',1,FP.Identifiers.Count); AssertEquals('One variable added',1,FP.Identifiers.Count);
AssertSame('Result equals variable added',I,FP.Identifiers[0]); AssertSame('Result equals variable added',I,FP.Identifiers[0]);
AssertEquals('Function has correct resulttype',rtString,I.ResultType); AssertEquals('Function has correct resulttype',rtString,I.ResultType);
@ -5507,6 +5679,7 @@ Var
begin begin
// Test type mismatch // Test type mismatch
I:=FP.Identifiers.AddFunction('AddInteger','I','II',@DoAddInteger); I:=FP.Identifiers.AddFunction('AddInteger','I','II',@DoAddInteger);
AssertNotNull('Addvariable returns result',I);
TestParser('AddInteger(3 and 2,''s'')'); TestParser('AddInteger(3 and 2,''s'')');
end; end;
@ -5589,6 +5762,21 @@ begin
AssertEquals('Variable has correct value',FloatToStr(1.23),I.Value); AssertEquals('Variable has correct value',FloatToStr(1.23),I.Value);
end; end;
procedure TTestBuiltinsManager.TestVariable7;
Var
I : TFPBuiltinExprIdentifierDef;
begin
I:=FM.AddCurrencyVariable(bcUser,'a',1.23);
AssertNotNull('Addvariable returns result',I);
AssertEquals('One variable added',1,FM.IdentifierCount);
AssertSame('Result equals variable added',I,FM.Identifiers[0]);
AssertEquals('Variable has correct category',ord(bcUser),Ord(I.Category));
AssertEquals('Variable has correct resulttype',rtCurrency,I.ResultType);
AssertEquals('Variable has correct value',CurrToStr(1.23),I.Value);
end;
procedure TTestBuiltinsManager.TestVariable5; procedure TTestBuiltinsManager.TestVariable5;
Var Var
@ -5786,6 +5974,21 @@ begin
AssertResult(AResult); AssertResult(AResult);
end; end;
procedure TTestBuiltins.AssertAggregateCurrExpression(Const AExpression : String; AResult : Currency; AUpdateCount : integer);
begin
FP.BuiltIns:=AllBuiltIns;
SetExpression(AExpression);
AssertEquals('Has aggregate',True,FP.ExprNode.HasAggregate);
FP.InitAggregate;
While AUpdateCount>0 do
begin
FP.UpdateAggregate;
Dec(AUpdateCount);
end;
AssertCurrencyResult(AResult);
end;
procedure TTestBuiltins.TestRegister; procedure TTestBuiltins.TestRegister;
begin begin
@ -6314,9 +6517,21 @@ end;
procedure TTestBuiltins.TestFunctionAggregateSum; procedure TTestBuiltins.TestFunctionAggregateSum;
begin begin
FP.Identifiers.AddIntegerVariable('S',2); FP.Identifiers.AddIntegerVariable('S',2);
AssertAggregateExpression('sum(S)',10,5);
end;
procedure TTestBuiltins.TestFunctionAggregateSumFloat;
begin
FP.Identifiers.AddFloatVariable('S',2.0);
AssertAggregateExpression('sum(S)',10.0,5); AssertAggregateExpression('sum(S)',10.0,5);
end; end;
procedure TTestBuiltins.TestFunctionAggregateSumCurrency;
begin
FP.Identifiers.AddCurrencyVariable('S',2.0);
AssertAggregateCurrExpression('sum(S)',Currency(10.0),5);
end;
procedure TTestBuiltins.TestFunctionAggregateCount; procedure TTestBuiltins.TestFunctionAggregateCount;
begin begin
AssertAggregateExpression('count',5,5); AssertAggregateExpression('count',5,5);
@ -6796,7 +7011,7 @@ end;
initialization initialization
RegisterTests([TTestExpressionScanner, TTestDestroyNode, RegisterTests('ExprPars',[TTestExpressionScanner, TTestDestroyNode,
TTestConstExprNode,TTestNegateExprNode, TTestConstExprNode,TTestNegateExprNode,
TTestBinaryAndNode,TTestBinaryOrNode,TTestBinaryXOrNode, TTestBinaryAndNode,TTestBinaryOrNode,TTestBinaryXOrNode,
TTestNotNode,TTestEqualNode,TTestUnEqualNode, TTestNotNode,TTestEqualNode,TTestUnEqualNode,