fpspreadsheet: remove type check in TsExpressionParser to be more compatible with Office applications. Fix parser to correctly handle exotic expressions such as "=50%^200%"

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4180 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2015-06-06 19:34:39 +00:00
parent 5d6bea6a85
commit 9fbe0f7b4e

View File

@ -110,14 +110,14 @@ type
private private
FParser: TsExpressionParser; FParser: TsExpressionParser;
protected protected
procedure CheckNodeType(ANode: TsExprNode; Allowed: TsResultTypes); // procedure CheckNodeType(ANode: TsExprNode; Allowed: TsResultTypes);
// A procedure with var saves an implicit try/finally in each node // A procedure with var saves an implicit try/finally in each node
// A marked difference in execution speed. // A marked difference in execution speed.
procedure GetNodeValue(out Result: TsExpressionResult); virtual; abstract; procedure GetNodeValue(out Result: TsExpressionResult); virtual; abstract;
public public
function AsRPNItem(ANext: PRPNItem): PRPNItem; virtual; abstract; function AsRPNItem(ANext: PRPNItem): PRPNItem; virtual; abstract;
function AsString: string; virtual; abstract; function AsString: string; virtual; abstract;
procedure Check; virtual; abstract; procedure Check; virtual; //abstract;
function NodeType: TsResultType; virtual; abstract; function NodeType: TsResultType; virtual; abstract;
function NodeValue: TsExpressionResult; function NodeValue: TsExpressionResult;
property Parser: TsExpressionParser read FParser; property Parser: TsExpressionParser read FParser;
@ -131,11 +131,11 @@ type
FLeft: TsExprNode; FLeft: TsExprNode;
FRight: TsExprNode; FRight: TsExprNode;
protected protected
procedure CheckSameNodeTypes; virtual; //procedure CheckSameNodeTypes; virtual;
public public
constructor Create(AParser: TsExpressionParser; ALeft, ARight: TsExprNode); constructor Create(AParser: TsExpressionParser; ALeft, ARight: TsExprNode);
destructor Destroy; override; destructor Destroy; override;
procedure Check; override; // procedure Check; override;
property Left: TsExprNode read FLeft; property Left: TsExprNode read FLeft;
property Right: TsExprNode read FRight; property Right: TsExprNode read FRight;
end; end;
@ -144,16 +144,16 @@ type
{ TsBooleanOperationExprNode } { TsBooleanOperationExprNode }
TsBooleanOperationExprNode = class(TsBinaryOperationExprNode) TsBooleanOperationExprNode = class(TsBinaryOperationExprNode)
public public
procedure Check; override; // procedure Check; override;
function NodeType: TsResultType; override; function NodeType: TsResultType; override;
end; end;
{ TsBooleanResultExprNode } { TsBooleanResultExprNode }
TsBooleanResultExprNode = class(TsBinaryOperationExprNode) TsBooleanResultExprNode = class(TsBinaryOperationExprNode)
protected protected
procedure CheckSameNodeTypes; override; // procedure CheckSameNodeTypes; override;
public public
procedure Check; override; // procedure Check; override;
function NodeType: TsResultType; override; function NodeType: TsResultType; override;
end; end;
TsBooleanResultExprNodeClass = class of TsBooleanResultExprNode; TsBooleanResultExprNodeClass = class of TsBooleanResultExprNode;
@ -179,7 +179,7 @@ type
{ TsOrderingExprNode } { TsOrderingExprNode }
TsOrderingExprNode = class(TsBooleanResultExprNode) TsOrderingExprNode = class(TsBooleanResultExprNode)
public public
procedure Check; override; // procedure Check; override;
end; end;
{ TsLessExprNode } { TsLessExprNode }
@ -221,21 +221,21 @@ type
{ TsConcatExprNode } { TsConcatExprNode }
TsConcatExprNode = class(TsBinaryOperationExprNode) TsConcatExprNode = class(TsBinaryOperationExprNode)
protected protected
procedure CheckSameNodeTypes; override; // procedure CheckSameNodeTypes; override;
procedure GetNodeValue(out Result: TsExpressionResult); override; procedure GetNodeValue(out Result: TsExpressionResult); override;
public public
function AsRPNItem(ANext: PRPNItem): PRPNItem; override; function AsRPNItem(ANext: PRPNItem): PRPNItem; override;
function AsString: string ; override; function AsString: string ; override;
procedure Check; override; // procedure Check; override;
function NodeType: TsResultType; override; function NodeType: TsResultType; override;
end; end;
{ TsMathOperationExprNode } { TsMathOperationExprNode }
TsMathOperationExprNode = class(TsBinaryOperationExprNode) TsMathOperationExprNode = class(TsBinaryOperationExprNode)
protected protected
procedure CheckSameNodeTypes; override; // procedure CheckSameNodeTypes; override;
public public
procedure Check; override; // procedure Check; override;
function NodeType: TsResultType; override; function NodeType: TsResultType; override;
end; end;
@ -317,7 +317,7 @@ type
{ TsConvertToIntExprNode } { TsConvertToIntExprNode }
TsConvertToIntExprNode = class(TsConvertExprNode) TsConvertToIntExprNode = class(TsConvertExprNode)
public public
procedure Check; override; // procedure Check; override;
end; end;
{ TsIntToFloatExprNode } { TsIntToFloatExprNode }
@ -341,7 +341,7 @@ type
protected protected
procedure GetNodeValue(out Result: TsExpressionResult); override; procedure GetNodeValue(out Result: TsExpressionResult); override;
public public
procedure Check; override; // procedure Check; override;
function NodeType: TsResultType; override; function NodeType: TsResultType; override;
end; end;
@ -352,7 +352,7 @@ type
public public
function AsRPNItem(ANext: PRPNItem): PRPNItem; override; function AsRPNItem(ANext: PRPNItem): PRPNItem; override;
function AsString: String; override; function AsString: String; override;
procedure Check; override; // procedure Check; override;
function NodeType: TsResultType; override; function NodeType: TsResultType; override;
end; end;
@ -363,7 +363,7 @@ type
public public
function AsRPNItem(ANext: PRPNItem): PRPNItem; override; function AsRPNItem(ANext: PRPNItem): PRPNItem; override;
function AsString: String; override; function AsString: String; override;
procedure Check; override; // procedure Check; override;
function NodeType: TsResultType; override; function NodeType: TsResultType; override;
end; end;
@ -729,6 +729,7 @@ type
function Level4: TsExprNode; function Level4: TsExprNode;
function Level5: TsExprNode; function Level5: TsExprNode;
function Level6: TsExprNode; function Level6: TsExprNode;
function Level7: TsExprNode;
function Primitive: TsExprNode; function Primitive: TsExprNode;
function TokenType: TsTokenType; function TokenType: TsTokenType;
procedure CreateHashList; procedure CreateHashList;
@ -1572,34 +1573,82 @@ end;
function TsExpressionParser.Level5: TsExprNode; function TsExpressionParser.Level5: TsExprNode;
var var
isPlus, isMinus: Boolean; tt: TsTokenType;
right: TsExprNode;
begin begin
{$ifdef debugexpr} Writeln('Level 5 ',TokenName(TokenType),': ',CurrentToken);{$endif debugexpr} {$ifdef debugexpr} Writeln('Level 5 ',TokenName(TokenType),': ',CurrentToken);{$endif debugexpr}
isPlus := false;
isMinus := false;
if (TokenType in [ttPlus, ttMinus]) then
begin
isPlus := (TokenType = ttPlus);
isMinus := (TokenType = ttMinus);
GetToken;
end;
Result := Level6; Result := Level6;
if isPlus then try
Result := TsUPlusExprNode.Create(self, Result); while (TokenType = ttPower) do
if isMinus then begin
Result := TsUMinusExprNode.Create(self, Result); tt := TokenType;
if TokenType = ttPercent then begin GetToken;
Result := TsPercentExprNode.Create(self, Result); right := Level6;
GetToken; CheckNodes(Result, right);
Result := TsPowerExprNode.Create(self, Result, right);
end;
except
Result.Free;
Raise;
end; end;
end; end;
function TsExpressionParser.Level6: TsExprNode; function TsExpressionParser.Level6: TsExprNode;
var
//isPlus, isMinus: Boolean;
signs: String;
i: Integer;
begin
{$ifdef debugexpr} Writeln('Level 6 ',TokenName(TokenType),': ',CurrentToken);{$endif debugexpr}
// isPlus := false;
// isMinus := false;
signs := '';
while (TokenType in [ttPlus, ttMinus]) do
begin
case TokenType of
ttPlus : signs := signs + '+';
ttMinus : signs := signs + '-';
end;
{
isPlus := (TokenType = ttPlus);
isMinus := (TokenType = ttMinus);
}
GetToken;
end;
Result := Level7;
i := Length(signs);
while (i > 0) do begin
case signs[i] of
'+': Result := TsUPlusExprNode.Create(self, Result);
'-': Result := TsUMinusExprNode.Create(self, Result);
end;
dec(i);
end;
{
if isPlus then
Result := TsUPlusExprNode.Create(self, Result);
if isMinus then
Result := TsUMinusExprNode.Create(self, Result);
}
while TokenType = ttPercent do begin
Result := TsPercentExprNode.Create(self, Result);
GetToken;
end;
{
if TokenType = ttPercent then begin
Result := TsPercentExprNode.Create(self, Result);
GetToken;
end;
}
end;
function TsExpressionParser.Level7: TsExprNode;
var var
Right: TsExprNode; Right: TsExprNode;
currToken: String; currToken: String;
begin begin
{$ifdef debugexpr} Writeln('Level 6 ',TokenName(TokenType),': ',CurrentToken);{$endif debugexpr} {$ifdef debugexpr} Writeln('Level 7 ',TokenName(TokenType),': ',CurrentToken);{$endif debugexpr}
if (TokenType = ttLeft) then if (TokenType = ttLeft) then
begin begin
GetToken; GetToken;
@ -1618,13 +1667,13 @@ begin
end end
else else
Result := Primitive; Result := Primitive;
{
if TokenType = ttPower then if TokenType = ttPower then
begin begin
try try
CheckEOF; CheckEOF;
GetToken; GetToken;
Right := Primitive; Right := Level1; //Primitive;
CheckNodes(Result, right); CheckNodes(Result, right);
Result := TsPowerExprNode.Create(self, Result, Right); Result := TsPowerExprNode.Create(self, Result, Right);
//GetToken; //GetToken;
@ -1632,7 +1681,13 @@ begin
Result.Free; Result.Free;
raise; raise;
end; end;
end; }
{
if TokenType = ttPercent then begin
Result := TsPercentExprNode.Create(self, Result);
GetToken;
end; end;
}
end; end;
{ Checks types of todo and match. If ToDO can be converted to it matches { Checks types of todo and match. If ToDO can be converted to it matches
@ -2554,7 +2609,11 @@ end;
{------------------------------------------------------------------------------} {------------------------------------------------------------------------------}
{ TsExprNode } { TsExprNode }
procedure TsExprNode.Check;
begin
end;
{
procedure TsExprNode.CheckNodeType(ANode: TsExprNode; Allowed: TsResultTypes); procedure TsExprNode.CheckNodeType(ANode: TsExprNode; Allowed: TsResultTypes);
var var
S: String; S: String;
@ -2575,7 +2634,7 @@ begin
RaiseParserError(SInvalidNodeType, [ResultTypeName(ANode.NodeType), S, ANode.AsString]); RaiseParserError(SInvalidNodeType, [ResultTypeName(ANode.NodeType), S, ANode.AsString]);
end; end;
end; end;
}
function TsExprNode.NodeValue: TsExpressionResult; function TsExprNode.NodeValue: TsExpressionResult;
begin begin
GetNodeValue(Result); GetNodeValue(Result);
@ -2620,7 +2679,7 @@ begin
FreeAndNil(FRight); FreeAndNil(FRight);
inherited Destroy; inherited Destroy;
end; end;
{
procedure TsBinaryOperationExprNode.Check; procedure TsBinaryOperationExprNode.Check;
begin begin
if not Assigned(Left) then if not Assigned(Left) then
@ -2638,10 +2697,11 @@ begin
if (RT <> LT) then if (RT <> LT) then
RaiseParserError(SErrTypesDoNotMatch, [ResultTypeName(LT), ResultTypeName(RT), Left.AsString, Right.AsString]) RaiseParserError(SErrTypesDoNotMatch, [ResultTypeName(LT), ResultTypeName(RT), Left.AsString, Right.AsString])
end; end;
}
{ TsBooleanOperationExprNode } { TsBooleanOperationExprNode }
{
procedure TsBooleanOperationExprNode.Check; procedure TsBooleanOperationExprNode.Check;
begin begin
inherited Check; inherited Check;
@ -2649,7 +2709,7 @@ begin
CheckNodeType(Right, [rtBoolean, rtCell, rtError, rtEmpty]); CheckNodeType(Right, [rtBoolean, rtCell, rtError, rtEmpty]);
CheckSameNodeTypes; CheckSameNodeTypes;
end; end;
}
function TsBooleanOperationExprNode.NodeType: TsResultType; function TsBooleanOperationExprNode.NodeType: TsResultType;
begin begin
Result := Left.NodeType; Result := Left.NodeType;
@ -2806,7 +2866,7 @@ function TsUPlusExprNode.AsString: String;
begin begin
Result := '+' + TrimLeft(Operand.AsString); Result := '+' + TrimLeft(Operand.AsString);
end; end;
{
procedure TsUPlusExprNode.Check; procedure TsUPlusExprNode.Check;
const const
AllowedTokens = [rtInteger, rtFloat, rtCell, rtEmpty, rtError]; AllowedTokens = [rtInteger, rtFloat, rtCell, rtEmpty, rtError];
@ -2815,7 +2875,7 @@ begin
if not (Operand.NodeType in AllowedTokens) then if not (Operand.NodeType in AllowedTokens) then
RaiseParserError(SErrNoUPlus, [ResultTypeName(Operand.NodeType), Operand.AsString]) RaiseParserError(SErrNoUPlus, [ResultTypeName(Operand.NodeType), Operand.AsString])
end; end;
}
procedure TsUPlusExprNode.GetNodeValue(out Result: TsExpressionResult); procedure TsUPlusExprNode.GetNodeValue(out Result: TsExpressionResult);
var var
cell: PCell; cell: PCell;
@ -2865,7 +2925,7 @@ function TsUMinusExprNode.AsString: String;
begin begin
Result := '-' + TrimLeft(Operand.AsString); Result := '-' + TrimLeft(Operand.AsString);
end; end;
{
procedure TsUMinusExprNode.Check; procedure TsUMinusExprNode.Check;
const const
AllowedTokens = [rtInteger, rtFloat, rtCell, rtEmpty, rtError]; AllowedTokens = [rtInteger, rtFloat, rtCell, rtEmpty, rtError];
@ -2874,7 +2934,7 @@ begin
if not (Operand.NodeType in AllowedTokens) then if not (Operand.NodeType in AllowedTokens) then
RaiseParserError(SErrNoNegation, [ResultTypeName(Operand.NodeType), Operand.AsString]) RaiseParserError(SErrNoNegation, [ResultTypeName(Operand.NodeType), Operand.AsString])
end; end;
}
procedure TsUMinusExprNode.GetNodeValue(out Result: TsExpressionResult); procedure TsUMinusExprNode.GetNodeValue(out Result: TsExpressionResult);
var var
cell: PCell; cell: PCell;
@ -3020,17 +3080,17 @@ end;
{ TsBooleanResultExprNode } { TsBooleanResultExprNode }
{
procedure TsBooleanResultExprNode.Check; procedure TsBooleanResultExprNode.Check;
begin begin
inherited Check; inherited Check;
CheckSameNodeTypes; //CheckSameNodeTypes;
end; end;
procedure TsBooleanResultExprNode.CheckSameNodeTypes; procedure TsBooleanResultExprNode.CheckSameNodeTypes;
begin begin
// Same node types are checked in GetNodevalue // Same node types are checked in GetNodevalue
end; end; }
function TsBooleanResultExprNode.NodeType: TsResultType; function TsBooleanResultExprNode.NodeType: TsResultType;
begin begin
@ -3115,7 +3175,7 @@ end;
{ TsOrderingExprNode } { TsOrderingExprNode }
{
procedure TsOrderingExprNode.Check; procedure TsOrderingExprNode.Check;
const const
AllowedTypes = [rtBoolean, rtInteger, rtFloat, rtDateTime, rtString, rtEmpty, rtError, rtCell]; AllowedTypes = [rtBoolean, rtInteger, rtFloat, rtDateTime, rtString, rtEmpty, rtError, rtCell];
@ -3124,7 +3184,7 @@ begin
CheckNodeType(Right, AllowedTypes); CheckNodeType(Right, AllowedTypes);
inherited Check; inherited Check;
end; end;
}
{ TsLessExprNode } { TsLessExprNode }
@ -3281,19 +3341,19 @@ function TsConcatExprNode.AsString: string;
begin begin
Result := Left.AsString + '&' + Right.AsString; Result := Left.AsString + '&' + Right.AsString;
end; end;
{
procedure TsConcatExprNode.Check; procedure TsConcatExprNode.Check;
begin begin
inherited Check; inherited Check;
CheckNodeType(Left, [rtString, rtCell, rtEmpty, rtError]); //CheckNodeType(Left, [rtString, rtCell, rtEmpty, rtError]);
CheckNodeType(Right, [rtString, rtCell, rtEmpty, rtError]); //CheckNodeType(Right, [rtString, rtCell, rtEmpty, rtError]);
end; end;
procedure TsConcatExprNode.CheckSameNodeTypes; procedure TsConcatExprNode.CheckSameNodeTypes;
begin begin
// Same node types are checked in GetNodevalue // Same node types are checked in GetNodevalue
end; end;
}
procedure TsConcatExprNode.GetNodeValue(out Result: TsExpressionResult); procedure TsConcatExprNode.GetNodeValue(out Result: TsExpressionResult);
var var
RRes : TsExpressionResult; RRes : TsExpressionResult;
@ -3302,6 +3362,11 @@ begin
if (Result.ResultType = rtError) if (Result.ResultType = rtError)
then exit; then exit;
Right.GetNodeValue(RRes); Right.GetNodeValue(RRes);
if RRes.ResultType = rtError then
Result := ErrorResult(RRes.ResError);
Result := StringResult(ArgToString(Result) + ArgToString(RRes));
{
if (Result.ResultType in [rtString, rtCell]) and (RRes.ResultType in [rtString, rtCell]) if (Result.ResultType in [rtString, rtCell]) and (RRes.ResultType in [rtString, rtCell])
then Result := StringResult(ArgToString(Result) + ArgToString(RRes)) then Result := StringResult(ArgToString(Result) + ArgToString(RRes))
else else
@ -3309,6 +3374,7 @@ begin
then Result := ErrorResult(RRes.ResError) then Result := ErrorResult(RRes.ResError)
else else
Result := ErrorResult(errWrongType); Result := ErrorResult(errWrongType);
}
end; end;
function TsConcatExprNode.NodeType: TsResultType; function TsConcatExprNode.NodeType: TsResultType;
@ -3318,7 +3384,7 @@ end;
{ TsMathOperationExprNode } { TsMathOperationExprNode }
{
procedure TsMathOperationExprNode.Check; procedure TsMathOperationExprNode.Check;
const const
AllowedTypes = [rtInteger, rtFloat, rtDateTime, rtCell, rtEmpty, rtError]; AllowedTypes = [rtInteger, rtFloat, rtDateTime, rtCell, rtEmpty, rtError];
@ -3333,6 +3399,7 @@ procedure TsMathOperationExprNode.CheckSameNodeTypes;
begin begin
// Same node types are checked in GetNodevalue // Same node types are checked in GetNodevalue
end; end;
}
function TsMathOperationExprNode.NodeType: TsResultType; function TsMathOperationExprNode.NodeType: TsResultType;
begin begin
@ -3579,13 +3646,13 @@ end;
{ TsIntToFloatExprNode } { TsIntToFloatExprNode }
{
procedure TsConvertToIntExprNode.Check; procedure TsConvertToIntExprNode.Check;
begin begin
inherited Check; inherited Check;
CheckNodeType(Operand, [rtInteger, rtCell]) CheckNodeType(Operand, [rtInteger, rtCell])
end; end;
}
procedure TsIntToFloatExprNode.GetNodeValue(out Result: TsExpressionResult); procedure TsIntToFloatExprNode.GetNodeValue(out Result: TsExpressionResult);
begin begin
Operand.GetNodeValue(Result); Operand.GetNodeValue(Result);
@ -3615,13 +3682,13 @@ end;
{ TsFloatToDateTimeExprNode } { TsFloatToDateTimeExprNode }
{
procedure TsFloatToDateTimeExprNode.Check; procedure TsFloatToDateTimeExprNode.Check;
begin begin
inherited Check; inherited Check;
CheckNodeType(Operand, [rtFloat, rtCell]); CheckNodeType(Operand, [rtFloat, rtCell]);
end; end;
}
function TsFloatToDateTimeExprNode.NodeType: TsResultType; function TsFloatToDateTimeExprNode.NodeType: TsResultType;
begin begin
Result := rtDateTime; Result := rtDateTime;