1 {
2  ---------------------------------------------------------------------------
3  FpPascalParser.pas  -  Native Freepascal debugger - Parse pascal expressions
4  ---------------------------------------------------------------------------
5 
6  ***************************************************************************
7  *                                                                         *
8  *   This source is free software; you can redistribute it and/or modify   *
9  *   it under the terms of the GNU General Public License as published by  *
10  *   the Free Software Foundation; either version 2 of the License, or     *
11  *   (at your option) any later version.                                   *
12  *                                                                         *
13  *   This code is distributed in the hope that it will be useful, but      *
14  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
16  *   General Public License for more details.                              *
17  *                                                                         *
18  *   A copy of the GNU General Public License is available on the World    *
19  *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
20  *   obtain it by writing to the Free Software Foundation,                 *
21  *   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.   *
22  *                                                                         *
23  ***************************************************************************
24 }
25 unit FpPascalParser;
26 
27 {$mode objfpc}{$H+}
28 {$TYPEDADDRESS on}
29 
30 interface
31 
32 uses
33   Classes, sysutils, math, DbgIntfBaseTypes, FpDbgInfo, FpdMemoryTools,
34   FpErrorMessages, FpDbgDwarf, {$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif}, LazClasses;
35 
36 type
37 
38   TFpPascalExpressionPartList= class;
39 
40   TFpPascalExpressionPart = class;
41   TFpPascalExpressionPartContainer = class;
42   TFpPascalExpressionPartWithPrecedence = class;
43   TFpPascalExpressionPartBracket = class;
44   TFpPascalExpressionPartOperator = class;
45 
46   TFpPascalExpressionPartClass = class of TFpPascalExpressionPart;
47   TFpPascalExpressionPartBracketClass = class of TFpPascalExpressionPartBracket;
48 
49   TSeparatorType = (ppstComma);
50 
51   TFpPascalParserCallFunctionProc = function (AnExpressionPart: TFpPascalExpressionPart;
52     AFunctionValue: TFpValue; ASelfValue: TFpValue; AParams: TFpPascalExpressionPartList;
53     out AResult: TFpValue; var AnError: TFpError): boolean of object;
54 
55   { TFpPascalExpression }
56 
57   TFpPascalExpression = class
58   private
59     FError: TFpError;
60     FContext: TFpDbgSymbolScope;
61     FFixPCharIndexAccess: Boolean;
62     FHasPCharIndexAccess: Boolean;
63     FOnFunctionCall: TFpPascalParserCallFunctionProc;
64     FTextExpression: String;
65     FExpressionPart: TFpPascalExpressionPart;
66     FValid: Boolean;
GetResultValuenull67     function GetResultValue: TFpValue;
GetValidnull68     function GetValid: Boolean;
69     procedure Parse;
70     procedure SetError(AMsg: String);  // deprecated;
71     procedure SetError(AnErrorCode: TFpErrorCode; AData: array of const);
72     procedure SetError(const AnErr: TFpError);
PosFromPCharnull73     function PosFromPChar(APChar: PChar): Integer;
74   protected
GetDbgSymbolForIdentifiernull75     function GetDbgSymbolForIdentifier({%H-}AnIdent: String): TFpValue;
76     property ExpressionPart: TFpPascalExpressionPart read FExpressionPart;
77     property Context: TFpDbgSymbolScope read FContext;
78   public
79     constructor Create(ATextExpression: String; AContext: TFpDbgSymbolScope);
80     destructor Destroy; override;
DebugDumpnull81     function DebugDump(AWithResults: Boolean = False): String;
82     procedure ResetEvaluation;
83     property TextExpression: String read FTextExpression;
84     property Error: TFpError read FError;
85     property Valid: Boolean read GetValid;
86     // Set by GetResultValue
87     property HasPCharIndexAccess: Boolean read FHasPCharIndexAccess;
88     // handle pchar as string (adjust index)
89     property FixPCharIndexAccess: Boolean read FFixPCharIndexAccess write FFixPCharIndexAccess;
90     // ResultValue
91     // - May be a type, if expression is a type
92     // - Only valid, as long as the expression is not destroyed
93     property ResultValue: TFpValue read GetResultValue;
94     property OnFunctionCall: TFpPascalParserCallFunctionProc read FOnFunctionCall write FOnFunctionCall;
95   end;
96 
97 
98   { TFpPascalExpressionPartList }
99 
100   TFpPascalExpressionPartList = class
101   protected
GetItemsnull102     function GetItems(AIndex: Integer): TFpPascalExpressionPart; virtual; abstract;
GetCountnull103     function GetCount: Integer; virtual; abstract;
104   public
105     property Count: Integer read GetCount;
106     property Items[AIndex: Integer]: TFpPascalExpressionPart read GetItems;
107   end;
108 
109   { TFpPascalExpressionPart }
110 
111   TFpPascalExpressionPart = class
112   private
113     FEndChar: PChar;
114     FParent: TFpPascalExpressionPartContainer;
115     FStartChar: PChar;
116     FExpression: TFpPascalExpression;
117     FResultValue: TFpValue;
118     FResultValDone: Boolean;
GetResultValuenull119     function GetResultValue: TFpValue;
GetSurroundingOpenBracketnull120     function GetSurroundingOpenBracket: TFpPascalExpressionPartBracket;
GetTopParentnull121     function GetTopParent: TFpPascalExpressionPart;
122     procedure SetEndChar(AValue: PChar);
123     procedure SetParent(AValue: TFpPascalExpressionPartContainer);
124     procedure SetStartChar(AValue: PChar);
125     procedure SetError(AMsg: String = ''); // deprecated;
126     procedure SetError(APart: TFpPascalExpressionPart; AMsg: String = ''); // deprecated;
127     procedure SetError(AnErrorCode: TFpErrorCode; AData: array of const);
128   protected
DebugTextnull129     function DebugText(AIndent: String; {%H-}AWithResults: Boolean): String; virtual; // Self desc only
DebugDumpnull130     function DebugDump(AIndent: String; AWithResults: Boolean): String; virtual;
131   protected
132     procedure Init; virtual;
DoGetIsTypeCastnull133     function  DoGetIsTypeCast: Boolean; virtual; deprecated;
DoGetResultValuenull134     function  DoGetResultValue: TFpValue; virtual;
135     procedure ResetEvaluation;
136 
137     Procedure ReplaceInParent(AReplacement: TFpPascalExpressionPart);
138     procedure DoHandleEndOfExpression; virtual;
139 
IsValidNextPartnull140     function IsValidNextPart(APart: TFpPascalExpressionPart): Boolean; virtual;
IsValidAfterPartnull141     function IsValidAfterPart({%H-}APrevPart: TFpPascalExpressionPart): Boolean; virtual;
MaybeHandlePrevPartnull142     function MaybeHandlePrevPart({%H-}APrevPart: TFpPascalExpressionPart;
143                                  var {%H-}AResult: TFpPascalExpressionPart): Boolean; virtual;
144     // HasPrecedence: an operator with follows precedence rules: the last operand can be taken by the next operator
HasPrecedencenull145     function HasPrecedence: Boolean; virtual;
FindLeftSideOperandByPrecedencenull146     function FindLeftSideOperandByPrecedence({%H-}AnOperator: TFpPascalExpressionPartWithPrecedence):
147                                              TFpPascalExpressionPart; virtual;
CanHaveOperatorAsNextnull148     function CanHaveOperatorAsNext: Boolean; virtual; // True
HandleSeparatornull149     function HandleSeparator(ASeparatorType: TSeparatorType): Boolean; virtual; // False
150   public
151     constructor Create(AExpression: TFpPascalExpression; AStartChar: PChar; AnEndChar: PChar = nil);
152     destructor Destroy; override;
HandleNextPartnull153     function  HandleNextPart(APart: TFpPascalExpressionPart): TFpPascalExpressionPart; virtual;
154     procedure HandleEndOfExpression; virtual;
155 
GetTextnull156     function GetText(AMaxLen: Integer=0): String;
157     property StartChar: PChar read FStartChar write SetStartChar;
158     property EndChar: PChar read FEndChar write SetEndChar;
159     property Parent: TFpPascalExpressionPartContainer read FParent write SetParent;
160     property TopParent: TFpPascalExpressionPart read GetTopParent; // or self
161     property SurroundingBracket: TFpPascalExpressionPartBracket read GetSurroundingOpenBracket; // incl self
162     property ResultValue: TFpValue read GetResultValue;
163     property Expression: TFpPascalExpression read FExpression;
164   end;
165 
166   { TFpPascalExpressionPartContainer }
167 
168   TFpPascalExpressionPartContainer = class(TFpPascalExpressionPart)
169   private
170     FList: TList;
GetCountnull171     function GetCount: Integer;
GetItemsnull172     function GetItems(AIndex: Integer): TFpPascalExpressionPart;
GetLastItemnull173     function GetLastItem: TFpPascalExpressionPart;
174     procedure SetItems(AIndex: Integer; AValue: TFpPascalExpressionPart);
175     procedure SetLastItem(AValue: TFpPascalExpressionPart);
176   protected
177     procedure Init; override;
DebugDumpnull178     function DebugDump(AIndent: String; AWithResults: Boolean): String; override;
179   public
180     destructor Destroy; override;
Addnull181     function Add(APart: TFpPascalExpressionPart): Integer;
IndexOfnull182     function IndexOf(APart: TFpPascalExpressionPart): Integer;
183     procedure Clear;
184     property Count: Integer read GetCount;
185     property Items[AIndex: Integer]: TFpPascalExpressionPart read GetItems write SetItems;
186     property LastItem: TFpPascalExpressionPart read GetLastItem write SetLastItem;
187   end;
188 
189   { TFpPascalExpressionPartIdentifier }
190 
191   TFpPascalExpressionPartIdentifier = class(TFpPascalExpressionPartContainer)
192   protected
DoGetIsTypeCastnull193     function DoGetIsTypeCast: Boolean; override;
DoGetResultValuenull194     function DoGetResultValue: TFpValue; override;
195   end;
196 
197   TFpPascalExpressionPartConstant = class(TFpPascalExpressionPartContainer)
198   end;
199 
200   { TFpPascalExpressionPartConstantNumber }
201 
202   TFpPascalExpressionPartConstantNumber = class(TFpPascalExpressionPartConstant)
203   protected
DoGetResultValuenull204     function DoGetResultValue: TFpValue; override;
205   end;
206 
207   { TFpPascalExpressionPartConstantNumberFloat }
208 
209   TFpPascalExpressionPartConstantNumberFloat = class(TFpPascalExpressionPartConstantNumber)
210   protected
DoGetResultValuenull211     function DoGetResultValue: TFpValue; override;
212   end;
213 
214   { TFpPascalExpressionPartConstantText }
215 
216   TFpPascalExpressionPartConstantText = class(TFpPascalExpressionPartConstant)
217   protected
218     FValue: String;
DoGetResultValuenull219     function DoGetResultValue: TFpValue; override;
220   end;
221 
222   { TFpPascalExpressionPartWithPrecedence }
223 
224   TFpPascalExpressionPartWithPrecedence = class(TFpPascalExpressionPartContainer)
225   protected
226     FPrecedence: Integer;
HasPrecedencenull227     function HasPrecedence: Boolean; override;
228   public
229     property Precedence: Integer read FPrecedence;
230   end;
231 
232   { TFpPascalExpressionPartBracket }
233 
234   TFpPascalExpressionPartBracket = class(TFpPascalExpressionPartWithPrecedence)
235   // some, but not all bracket expr have precedence
236   private
237     FIsClosed: boolean;
238     FIsClosing: boolean;
239     FAfterComma: Integer;
GetAfterCommanull240     function GetAfterComma: Boolean;
241   protected
242     procedure Init; override;
HasPrecedencenull243     function HasPrecedence: Boolean; override;
244     procedure DoHandleEndOfExpression; override;
CanHaveOperatorAsNextnull245     function CanHaveOperatorAsNext: Boolean; override;
HandleNextPartInBracketnull246     function HandleNextPartInBracket(APart: TFpPascalExpressionPart): TFpPascalExpressionPart; virtual;
247     procedure SetAfterCommaFlag;
248     property AfterComma: Boolean read GetAfterComma;
249   public
250     procedure CloseBracket;
HandleNextPartnull251     function HandleNextPart(APart: TFpPascalExpressionPart): TFpPascalExpressionPart; override;
252     procedure HandleEndOfExpression; override;
253     property IsClosed: boolean read FIsClosed;
254   end;
255 
256   { TFpPascalExpressionPartRoundBracket }
257 
258   TFpPascalExpressionPartRoundBracket = class(TFpPascalExpressionPartBracket)
259   protected
260   end;
261 
262   { TFpPascalExpressionPartBracketSubExpression }
263 
264   TFpPascalExpressionPartBracketSubExpression = class(TFpPascalExpressionPartRoundBracket)
265   protected
HandleNextPartInBracketnull266     function HandleNextPartInBracket(APart: TFpPascalExpressionPart): TFpPascalExpressionPart; override;
DoGetResultValuenull267     function DoGetResultValue: TFpValue; override;
268   end;
269 
270   { TFpPascalExpressionPartBracketArgumentList }
271 
272   TFpPascalExpressionPartBracketArgumentList = class(TFpPascalExpressionPartRoundBracket)
argumentsnull273   // function arguments or type cast // this acts a operator: first element is the function/type
274   protected
275     procedure Init; override;
DoGetResultValuenull276     function DoGetResultValue: TFpValue; override;
DoGetIsTypeCastnull277     function DoGetIsTypeCast: Boolean; override;
IsValidAfterPartnull278     function IsValidAfterPart(APrevPart: TFpPascalExpressionPart): Boolean; override;
HandleNextPartInBracketnull279     function HandleNextPartInBracket(APart: TFpPascalExpressionPart): TFpPascalExpressionPart; override;
MaybeHandlePrevPartnull280     function MaybeHandlePrevPart(APrevPart: TFpPascalExpressionPart;
281       var AResult: TFpPascalExpressionPart): Boolean; override;
HandleSeparatornull282     function HandleSeparator(ASeparatorType: TSeparatorType): Boolean; override;
283   end;
284 
285 
286   { TFpPascalExpressionPartSquareBracket }
287 
288   TFpPascalExpressionPartSquareBracket = class(TFpPascalExpressionPartBracket)
289   end;
290 
291   { TFpPascalExpressionPartBracketSet }
292 
293   TFpPascalExpressionPartBracketSet = class(TFpPascalExpressionPartSquareBracket)
294   // a in [x, y, z]
295   protected
HandleNextPartInBracketnull296     function HandleNextPartInBracket(APart: TFpPascalExpressionPart): TFpPascalExpressionPart; override;
HandleSeparatornull297     function HandleSeparator(ASeparatorType: TSeparatorType): Boolean; override;
298   end;
299 
300   { TFpPascalExpressionPartBracketIndex }
301 
302   TFpPascalExpressionPartBracketIndex = class(TFpPascalExpressionPartSquareBracket)
303   // array[1]
304   protected
305     procedure Init; override;
DoGetResultValuenull306     function DoGetResultValue: TFpValue; override;
IsValidAfterPartnull307     function IsValidAfterPart(APrevPart: TFpPascalExpressionPart): Boolean; override;
HandleNextPartInBracketnull308     function HandleNextPartInBracket(APart: TFpPascalExpressionPart): TFpPascalExpressionPart; override;
MaybeHandlePrevPartnull309     function MaybeHandlePrevPart(APrevPart: TFpPascalExpressionPart;
310       var AResult: TFpPascalExpressionPart): Boolean; override;
311     procedure DoHandleEndOfExpression; override;
HandleSeparatornull312     function HandleSeparator(ASeparatorType: TSeparatorType): Boolean; override;
313   end;
314 
315   { TFpPascalExpressionPartOperator }
316 
317   TFpPascalExpressionPartOperator = class(TFpPascalExpressionPartWithPrecedence)
318   protected
DebugTextnull319     function DebugText(AIndent: String; AWithResults: Boolean): String; override;
CanHaveOperatorAsNextnull320     function CanHaveOperatorAsNext: Boolean; override;
FindLeftSideOperandByPrecedencenull321     function FindLeftSideOperandByPrecedence(AnOperator: TFpPascalExpressionPartWithPrecedence):
322                                              TFpPascalExpressionPart; override;
HasAllOperandsnull323     function HasAllOperands: Boolean; virtual; abstract;
MaybeAddLeftOperandnull324     function MaybeAddLeftOperand(APrevPart: TFpPascalExpressionPart;
325       var AResult: TFpPascalExpressionPart): Boolean;
326     procedure DoHandleEndOfExpression; override;
HandleSeparatornull327     function HandleSeparator(ASeparatorType: TSeparatorType): Boolean; override;
328   public
HandleNextPartnull329     function HandleNextPart(APart: TFpPascalExpressionPart): TFpPascalExpressionPart; override;
330   end;
331 
332   { TFpPascalExpressionPartUnaryOperator }
333 
334   TFpPascalExpressionPartUnaryOperator = class(TFpPascalExpressionPartOperator)
335   protected
HasAllOperandsnull336     function HasAllOperands: Boolean; override;
337   public
338   end;
339 
340   { TFpPascalExpressionPartBinaryOperator }
341 
342   TFpPascalExpressionPartBinaryOperator = class(TFpPascalExpressionPartOperator)
343   protected
HasAllOperandsnull344     function HasAllOperands: Boolean; override;
IsValidAfterPartnull345     function IsValidAfterPart(APrevPart: TFpPascalExpressionPart): Boolean; override;
346   public
MaybeHandlePrevPartnull347     function MaybeHandlePrevPart(APrevPart: TFpPascalExpressionPart;
348       var AResult: TFpPascalExpressionPart): Boolean; override;
349   end;
350 
351   { TFpPascalExpressionPartOperatorAddressOf }
352 
353   TFpPascalExpressionPartOperatorAddressOf = class(TFpPascalExpressionPartUnaryOperator)  // @
354   protected
355     procedure Init; override;
DoGetResultValuenull356     function DoGetResultValue: TFpValue; override;
357   end;
358 
359   { TFpPascalExpressionPartOperatorMakeRef }
360 
361   TFpPascalExpressionPartOperatorMakeRef = class(TFpPascalExpressionPartUnaryOperator)  // ^TTYpe
362   protected
363     procedure Init; override;
IsValidNextPartnull364     function IsValidNextPart(APart: TFpPascalExpressionPart): Boolean; override;
DoGetResultValuenull365     function DoGetResultValue: TFpValue; override;
DoGetIsTypeCastnull366     function DoGetIsTypeCast: Boolean; override;
367   end;
368 
369   { TFpPascalExpressionPartOperatorDeRef }
370 
371   TFpPascalExpressionPartOperatorDeRef = class(TFpPascalExpressionPartUnaryOperator)  // ptrval^
372   protected
373     procedure Init; override;
DoGetResultValuenull374     function DoGetResultValue: TFpValue; override;
MaybeHandlePrevPartnull375     function MaybeHandlePrevPart(APrevPart: TFpPascalExpressionPart;
376       var AResult: TFpPascalExpressionPart): Boolean; override;
FindLeftSideOperandByPrecedencenull377     function FindLeftSideOperandByPrecedence({%H-}AnOperator: TFpPascalExpressionPartWithPrecedence):
378                                              TFpPascalExpressionPart;
379       override;
380     // IsValidAfterPart: same as binary op
IsValidAfterPartnull381     function IsValidAfterPart(APrevPart: TFpPascalExpressionPart): Boolean; override;
382   end;
383 
384   { TFpPascalExpressionPartOperatorUnaryPlusMinus }
385 
386   TFpPascalExpressionPartOperatorUnaryPlusMinus = class(TFpPascalExpressionPartUnaryOperator)  // + -
387   // Unary + -
388   protected
389     procedure Init; override;
DoGetResultValuenull390     function DoGetResultValue: TFpValue; override;
391   end;
392 
393   { TFpPascalExpressionPartOperatorPlusMinus }
394 
395   TFpPascalExpressionPartOperatorPlusMinus = class(TFpPascalExpressionPartBinaryOperator)  // + -
396   // Binary + -
397   protected
398     procedure Init; override;
DoGetResultValuenull399     function DoGetResultValue: TFpValue; override;
400   end;
401 
402   { TFpPascalExpressionPartOperatorMulDiv }
403 
404   TFpPascalExpressionPartOperatorMulDiv = class(TFpPascalExpressionPartBinaryOperator)    // * /
405   protected
406     procedure Init; override;
DoGetResultValuenull407     function DoGetResultValue: TFpValue; override;
408   end;
409 
410   { TFpPascalExpressionPartOperatorUnaryNot }
411 
412   TFpPascalExpressionPartOperatorUnaryNot = class(TFpPascalExpressionPartUnaryOperator)  // not
413   protected
414     procedure Init; override;
DoGetResultValuenull415     function DoGetResultValue: TFpValue; override;
416   end;
417 
418   { TFpPascalExpressionPartOperatorAnd }
419 
420   TFpPascalExpressionPartOperatorAnd = class(TFpPascalExpressionPartBinaryOperator)    // AND
421   protected
422     procedure Init; override;
DoGetResultValuenull423     function DoGetResultValue: TFpValue; override;
424   end;
425 
426   { TFpPascalExpressionPartOperatorOr }
427 
428   TFpPascalExpressionPartOperatorOr = class(TFpPascalExpressionPartBinaryOperator)    // OR XOR
429   public type
430     TOpOrType = (ootOr, ootXor);
431   protected
432     FOp: TOpOrType;
433     procedure Init; override;
DoGetResultValuenull434     function DoGetResultValue: TFpValue; override;
435   public
436     constructor Create(AExpression: TFpPascalExpression; AnOp: TOpOrType; AStartChar: PChar;
437       AnEndChar: PChar = nil);
438   end;
439 
440   { TFpPascalExpressionPartOperatorCompare }
441 
442   TFpPascalExpressionPartOperatorCompare = class(TFpPascalExpressionPartBinaryOperator)    // = < > <> ><
443   protected
444     procedure Init; override;
DoGetResultValuenull445     function DoGetResultValue: TFpValue; override;
446   end;
447 
448   { TFpPascalExpressionPartOperatorMemberOf }
449 
450   TFpPascalExpressionPartOperatorMemberOf = class(TFpPascalExpressionPartBinaryOperator)    // struct.member
451   protected
452     procedure Init; override;
IsValidNextPartnull453     function IsValidNextPart(APart: TFpPascalExpressionPart): Boolean; override;
DoGetResultValuenull454     function DoGetResultValue: TFpValue; override;
455   end;
456 
457 implementation
458 
459 const
460   // 1 highest
461   PRECEDENCE_MEMBER_OF  =  1;        // foo.bar
462   PRECEDENCE_MAKE_REF   =  1;        // ^TFoo
463   PRECEDENCE_ARG_LIST   =  2;        // foo() / TFoo()
464   PRECEDENCE_ARRAY_IDX  =  2;        // foo[1]
465   PRECEDENCE_DEREF      =  5;        // a^    // Precedence acts only to the left side
466   PRECEDENCE_ADRESS_OF  =  6;        // @a
467   //PRECEDENCE_POWER      = 10;        // ** (power) must be stronger than unary -
468   PRECEDENCE_UNARY_SIGN = 11;        // -a
469   PRECEDENCE_UNARY_NOT  = 11;        // NOT a
470   PRECEDENCE_MUL_DIV    = 12;        // a * b
471   PRECEDENCE_AND        = 12;        // a AND b
472   PRECEDENCE_PLUS_MINUS = 13;        // a + b
473   PRECEDENCE_OR         = 13;        // a OR b  // XOR
474   PRECEDENCE_COMPARE    = 20;        // a <> b // a=b
475 
476 type
477 
478   { TFpPascalExpressionPartListForwarder }
479 
480   TFpPascalExpressionPartListForwarder = class(TFpPascalExpressionPartList)
481   private
482     FExpressionPart: TFpPascalExpressionPartContainer;
483     FListOffset, FCount: Integer;
484   protected
GetCountnull485     function GetCount: Integer; override;
GetItemsnull486     function GetItems(AIndex: Integer): TFpPascalExpressionPart; override;
487   public
488     constructor Create(AnExpressionPart: TFpPascalExpressionPartContainer; AListOffset, ACount: Integer);
489   end;
490 
491   {%region  DebugSymbol }
492 
493   { TPasParserSymbolPointer
494     used by TFpPasParserValueMakeReftype.GetDbgSymbol
495   }
496 
497   TPasParserSymbolPointer = class(TFpSymbol)
498   private
499     FPointerLevels: Integer;
500     FPointedTo: TFpSymbol;
501     FContext: TFpDbgLocationContext;
502   protected
503     // NameNeeded //  "^TPointedTo"
504     procedure TypeInfoNeeded; override;
DoReadSizenull505     function DoReadSize(const AValueObj: TFpValue; out ASize: TFpDbgValueSize): Boolean; override;
506   public
507     constructor Create(const APointedTo: TFpSymbol; AContext: TFpDbgLocationContext; APointerLevels: Integer);
508     constructor Create(const APointedTo: TFpSymbol; AContext: TFpDbgLocationContext);
509     destructor Destroy; override;
TypeCastValuenull510     function TypeCastValue(AValue: TFpValue): TFpValue; override;
511   end;
512 
513   { TPasParserSymbolArrayDeIndex }
514 
515   TPasParserSymbolArrayDeIndex = class(TFpSymbolForwarder) // 1 index level off
516   private
517     FArray: TFpSymbol;
518   protected
519     //procedure ForwardToSymbolNeeded; override;
GetNestedSymbolCountnull520     function GetNestedSymbolCount: Integer; override;
GetNestedSymbolnull521     function GetNestedSymbol(AIndex: Int64): TFpSymbol; override;
522   public
523     constructor Create(const AnArray: TFpSymbol);
524     destructor Destroy; override;
525   end;
526 
527   {%endregion  DebugSymbol }
528 
529   {%region  DebugSymbolValue }
530 
531   { TFpPasParserValue }
532 
533   TFpPasParserValue = class(TFpValue)
534   private
535     FContext: TFpDbgLocationContext;
536   protected
DebugTextnull537     function DebugText(AIndent: String): String; virtual;
538   public
539     constructor Create(AContext: TFpDbgLocationContext);
540     property Context: TFpDbgLocationContext read FContext;
541   end;
542 
543   { TFpPasParserValueCastToPointer
544     used by TPasParserSymbolPointer.TypeCastValue (which is used by TFpPasParserValueMakeReftype.GetDbgSymbol)
545   }
546 
547   TFpPasParserValueCastToPointer = class(TFpPasParserValue)
548   private
549     FValue: TFpValue;
550     FTypeSymbol: TFpSymbol;
551   protected
DebugTextnull552     function DebugText(AIndent: String): String; override;
553   protected
GetKindnull554     function GetKind: TDbgSymbolKind; override;
GetFieldFlagsnull555     function GetFieldFlags: TFpValueFieldFlags; override;
GetTypeInfonull556     function GetTypeInfo: TFpSymbol; override;
GetAsCardinalnull557     function GetAsCardinal: QWord; override;
GetAddressnull558     function GetAddress: TFpDbgMemLocation; override;
GetDataAddressnull559     function GetDataAddress: TFpDbgMemLocation; override;
GetMembernull560     function GetMember(AIndex: Int64): TFpValue; override;
561   public
562     constructor Create(AValue: TFpValue; ATypeInfo: TFpSymbol; AContext: TFpDbgLocationContext);
563     destructor Destroy; override;
564   end;
565 
566   { TFpPasParserValueMakeReftype }
567 
568   TFpPasParserValueMakeReftype = class(TFpPasParserValue)
569   private
570     FSourceTypeSymbol, FTypeSymbol: TFpSymbol;
571     FRefLevel: Integer;
572   protected
DebugTextnull573     function DebugText(AIndent: String): String; override;
574   protected
GetDbgSymbolnull575     function GetDbgSymbol: TFpSymbol; override; // returns a TPasParserSymbolPointer
576   public
577     constructor Create(ATypeInfo: TFpSymbol; AContext: TFpDbgLocationContext);
578     destructor Destroy; override;
579     procedure IncRefLevel;
GetTypeCastedValuenull580     function GetTypeCastedValue(ADataVal: TFpValue): TFpValue; override;
581   end;
582 
583   { TFpPasParserValueDerefPointer
584     Used as address source in typecast
585   }
586 
587   TFpPasParserValueDerefPointer = class(TFpPasParserValue)
588   private
589     FValue: TFpValue;
590     FAddressOffset: Int64; // Add to address
591     FCardinal: QWord; // todo: TFpDbgMemLocation ?
592     FCardinalRead: Boolean;
593   protected
DebugTextnull594     function DebugText(AIndent: String): String; override;
595   protected
GetFieldFlagsnull596     function GetFieldFlags: TFpValueFieldFlags; override;
GetAddressnull597     function GetAddress: TFpDbgMemLocation; override;
DoGetSizenull598     function DoGetSize(out ASize: TFpDbgValueSize): Boolean; override;
GetAsCardinalnull599     function GetAsCardinal: QWord; override; // reads men
GetTypeInfonull600     function GetTypeInfo: TFpSymbol; override; // TODO: Cardinal? Why? // TODO: does not handle AOffset
601   public
602     constructor Create(AValue: TFpValue; AContext: TFpDbgLocationContext);
603     constructor Create(AValue: TFpValue; AContext: TFpDbgLocationContext; AOffset: Int64);
604     destructor Destroy; override;
605   end;
606 
607   { TFpPasParserValueAddressOf }
608 
609   TFpPasParserValueAddressOf = class(TFpPasParserValue)
610   private
611     FValue: TFpValue;
612     FTypeInfo: TFpSymbol;
GetPointedToValuenull613     function GetPointedToValue: TFpValue;
614   protected
DebugTextnull615     function DebugText(AIndent: String): String; override;
616   protected
GetKindnull617     function GetKind: TDbgSymbolKind; override;
GetFieldFlagsnull618     function GetFieldFlags: TFpValueFieldFlags; override;
GetAsIntegernull619     function GetAsInteger: Int64; override;
GetAsCardinalnull620     function GetAsCardinal: QWord; override;
GetTypeInfonull621     function GetTypeInfo: TFpSymbol; override;
GetDataAddressnull622     function GetDataAddress: TFpDbgMemLocation; override;
GetMembernull623     function GetMember(AIndex: Int64): TFpValue; override;
GetAsStringnull624     function GetAsString: AnsiString; override;
GetAsWideStringnull625     function GetAsWideString: WideString; override;
626   public
627     constructor Create(AValue: TFpValue; AContext: TFpDbgLocationContext);
628     destructor Destroy; override;
629     property PointedToValue: TFpValue read GetPointedToValue;
630   end;
631 
632   {%endregion  DebugSymbolValue }
633 
DbgsResultValuenull634 function DbgsResultValue(AVal: TFpValue; AIndent: String): String;
635 begin
636   if AVal is TFpPasParserValue then
637     Result := LineEnding + TFpPasParserValue(AVal).DebugText(AIndent)
638   else
639   if AVal <> nil then
640     Result := DbgSName(AVal) + '  DbsSym='+DbgSName(AVal.DbgSymbol)+' Type='+DbgSName(AVal.TypeInfo)
641   else
642     Result := DbgSName(AVal);
643 end;
644 
DbgsSymbolnull645 function DbgsSymbol(AVal: TFpSymbol; {%H-}AIndent: String): String;
646 begin
647   Result := DbgSName(AVal);
648 end;
649 
650 { TFpPascalExpressionPartListForwarder }
651 
GetCountnull652 function TFpPascalExpressionPartListForwarder.GetCount: Integer;
653 begin
654   Result := FCount;
655 end;
656 
TFpPascalExpressionPartListForwarder.GetItemsnull657 function TFpPascalExpressionPartListForwarder.GetItems(AIndex: Integer
658   ): TFpPascalExpressionPart;
659 begin
660   Result := FExpressionPart.Items[AIndex + FListOffset];
661 end;
662 
663 constructor TFpPascalExpressionPartListForwarder.Create(
664   AnExpressionPart: TFpPascalExpressionPartContainer; AListOffset,
665   ACount: Integer);
666 begin
667   FExpressionPart := AnExpressionPart;
668   FListOffset := AListOffset;
669   FCount := ACount;
670 end;
671 
DebugTextnull672 function TFpPasParserValue.DebugText(AIndent: String): String;
673 begin
674   Result := AIndent + DbgSName(Self)  + '  DbsSym='+DbgSName(DbgSymbol)+' Type='+DbgSName(TypeInfo) + LineEnding;
675 end;
676 
677 constructor TFpPasParserValue.Create(AContext: TFpDbgLocationContext);
678 begin
679   FContext := AContext;
680   inherited Create;
681 end;
682 
683 { TPasParserSymbolValueCastToPointer }
684 
TFpPasParserValueCastToPointer.DebugTextnull685 function TFpPasParserValueCastToPointer.DebugText(AIndent: String): String;
686 begin
687   Result := inherited DebugText(AIndent)
688           + AIndent + '-Value= ' + DbgsResultValue(FValue, AIndent + '  ') + LineEnding
689           + AIndent + '-Symbol = ' + DbgsSymbol(FTypeSymbol, AIndent + '  ') + LineEnding;
690 end;
691 
GetKindnull692 function TFpPasParserValueCastToPointer.GetKind: TDbgSymbolKind;
693 begin
694   Result := skPointer;
695 end;
696 
TFpPasParserValueCastToPointer.GetFieldFlagsnull697 function TFpPasParserValueCastToPointer.GetFieldFlags: TFpValueFieldFlags;
698 begin
699   if (FValue.FieldFlags * [svfAddress, svfOrdinal] <> [])
700   then
701     Result := [svfOrdinal, svfCardinal, svfSizeOfPointer, svfDataAddress]
702   else
703     Result := [];
704 end;
705 
GetTypeInfonull706 function TFpPasParserValueCastToPointer.GetTypeInfo: TFpSymbol;
707 begin
708   Result := FTypeSymbol;
709 end;
710 
TFpPasParserValueCastToPointer.GetAsCardinalnull711 function TFpPasParserValueCastToPointer.GetAsCardinal: QWord;
712 var
713   f: TFpValueFieldFlags;
714 begin
715   Result := 0;
716   f := FValue.FieldFlags;
717   if svfOrdinal in f then
718     Result := FValue.AsCardinal
719   else
720   if svfAddress in f then begin
721     if not FContext.ReadUnsignedInt(FValue.Address, SizeVal(FContext.SizeOfAddress), Result) then begin
722       Result := 0;
723       SetLastError(FContext.LastMemError);
724     end;
725   end
726   else begin
727     SetLastError(CreateError(fpErrAnyError, ['']));
728   end;
729 end;
730 
GetAddressnull731 function TFpPasParserValueCastToPointer.GetAddress: TFpDbgMemLocation;
732 begin
733   Result := FValue.Address;
734 end;
735 
TFpPasParserValueCastToPointer.GetDataAddressnull736 function TFpPasParserValueCastToPointer.GetDataAddress: TFpDbgMemLocation;
737 begin
738   Result := TargetLoc(TDbgPtr(AsCardinal));
739 end;
740 
TFpPasParserValueCastToPointer.GetMembernull741 function TFpPasParserValueCastToPointer.GetMember(AIndex: Int64): TFpValue;
742 var
743   ti: TFpSymbol;
744   addr: TFpDbgMemLocation;
745   Tmp: TFpValueConstAddress;
746   Size: TFpDbgValueSize;
747 begin
748   Result := nil;
749 
750   ti := FTypeSymbol.TypeInfo;
751   addr := DataAddress;
752   if not IsTargetAddr(addr) then begin
753     //LastError := CreateError(fpErrAnyError, ['Internal dereference error']);
754     exit;
755   end;
756   {$PUSH}{$R-}{$Q-} // TODO: check overflow
757   if (ti <> nil) and (AIndex <> 0) then begin
758     // Only test for hardcoded size. TODO: dwarf 3 could have variable size, but for char that is not expected
759     // TODO: Size of member[0] ?
760     if not ti.ReadSize(nil, Size) then begin
761       SetLastError(CreateError(fpErrAnyError, ['Can index element of unknown size']));
762       exit;
763     end;
764     AIndex := AIndex * SizeToFullBytes(Size);
765   end;
766   addr.Address := addr.Address + AIndex;
767   {$POP}
768 
769   Tmp := TFpValueConstAddress.Create(addr);
770   if ti <> nil then begin
771     Result := ti.TypeCastValue(Tmp);
772     if Result is TFpValueDwarfBase then
773       TFpValueDwarfBase(Result).Context := Context;
774     Tmp.ReleaseReference;
775   end
776   else
777     Result := Tmp;
778 end;
779 
780 constructor TFpPasParserValueCastToPointer.Create(AValue: TFpValue;
781   ATypeInfo: TFpSymbol; AContext: TFpDbgLocationContext);
782 begin
783   inherited Create(AContext);
784   FValue := AValue;
785   FValue.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FValue, 'TPasParserSymbolValueCastToPointer'){$ENDIF};
786   FTypeSymbol := ATypeInfo;
787   FTypeSymbol.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FTypeSymbol, 'TPasParserSymbolValueCastToPointer'){$ENDIF};
788   Assert((FTypeSymbol=nil) or (FTypeSymbol.Kind = skPointer), 'TPasParserSymbolValueCastToPointer.Create');
789 end;
790 
791 destructor TFpPasParserValueCastToPointer.Destroy;
792 begin
793   FValue.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FValue, 'TPasParserSymbolValueCastToPointer'){$ENDIF};
794   FTypeSymbol.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FTypeSymbol, 'TPasParserSymbolValueCastToPointer'){$ENDIF};
795   inherited Destroy;
796 end;
797 
798 { TPasParserSymbolValueMakeReftype }
799 
DebugTextnull800 function TFpPasParserValueMakeReftype.DebugText(AIndent: String): String;
801 begin
802   Result := inherited DebugText(AIndent)
803           + AIndent + '-RefLevel = ' + dbgs(FRefLevel) + LineEnding
804           + AIndent + '-SourceSymbol = ' + DbgsSymbol(FSourceTypeSymbol, AIndent + '  ') + LineEnding
805           + AIndent + '-Symbol = ' + DbgsSymbol(FTypeSymbol, AIndent + '  ') + LineEnding;
806 end;
807 
TFpPasParserValueMakeReftype.GetDbgSymbolnull808 function TFpPasParserValueMakeReftype.GetDbgSymbol: TFpSymbol;
809 begin
810   if FTypeSymbol = nil then begin
811     FTypeSymbol := TPasParserSymbolPointer.Create(FSourceTypeSymbol, FContext, FRefLevel);
812     {$IFDEF WITH_REFCOUNT_DEBUG}FTypeSymbol.DbgRenameReference(@FSourceTypeSymbol, 'TPasParserSymbolValueMakeReftype'){$ENDIF};
813   end;
814   Result := FTypeSymbol;
815 end;
816 
817 constructor TFpPasParserValueMakeReftype.Create(ATypeInfo: TFpSymbol;
818   AContext: TFpDbgLocationContext);
819 begin
820   inherited Create(AContext);
821   FSourceTypeSymbol := ATypeInfo;
822   FSourceTypeSymbol.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FSourceTypeSymbol, 'TPasParserSymbolValueMakeReftype'){$ENDIF};
823   FRefLevel := 1;
824 end;
825 
826 destructor TFpPasParserValueMakeReftype.Destroy;
827 begin
828   FSourceTypeSymbol.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FSourceTypeSymbol, 'TPasParserSymbolValueMakeReftype'){$ENDIF};
829   FTypeSymbol.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FSourceTypeSymbol, 'TPasParserSymbolValueMakeReftype'){$ENDIF};
830   inherited Destroy;
831 end;
832 
833 procedure TFpPasParserValueMakeReftype.IncRefLevel;
834 begin
835   inc(FRefLevel);
836 end;
837 
GetTypeCastedValuenull838 function TFpPasParserValueMakeReftype.GetTypeCastedValue(ADataVal: TFpValue): TFpValue;
839 begin
840   Result := DbgSymbol.TypeCastValue(ADataVal);
841   if Result is TFpValueDwarfBase then
842     TFpValueDwarfBase(Result).Context := Context;
843 end;
844 
845 
846 { TPasParserDerefPointerSymbolValue }
847 
DebugTextnull848 function TFpPasParserValueDerefPointer.DebugText(AIndent: String): String;
849 begin
850   Result := inherited DebugText(AIndent)
851           + AIndent + '-Value= ' + DbgsResultValue(FValue, AIndent + '  ') + LineEnding;
852 end;
853 
GetFieldFlagsnull854 function TFpPasParserValueDerefPointer.GetFieldFlags: TFpValueFieldFlags;
855 var
856   t: TFpSymbol;
857 begin
858   // MUST *NOT* have ordinal
859   Result := [svfAddress];
860   t := FValue.TypeInfo;
861   if t <> nil then t := t.TypeInfo;
862   if t <> nil then
863     if t.Kind = skPointer then begin
864       //Result := Result + [svfSizeOfPointer];
865       Result := Result + [svfSizeOfPointer, svfCardinal, svfOrdinal]; // TODO: svfCardinal ???
866     end
867     else
868       Result := Result + [svfSize];
869 end;
870 
GetAddressnull871 function TFpPasParserValueDerefPointer.GetAddress: TFpDbgMemLocation;
872 begin
873   Result := FValue.DataAddress;
874   Result := Context.ReadAddress(Result, SizeVal(Context.SizeOfAddress));
875   if IsValidLoc(Result) then begin
876     SetLastError(Context.LastMemError);
877     exit;
878   end;
879 
880   if FAddressOffset <> 0 then begin
881     assert(IsTargetAddr(Result ), 'TFpPasParserValueDerefPointer.GetAddress: TargetLoc(Result)');
882     if IsTargetAddr(Result) then
883       Result.Address := Result.Address + FAddressOffset
884     else
885       Result := InvalidLoc;
886   end;
887 end;
888 
DoGetSizenull889 function TFpPasParserValueDerefPointer.DoGetSize(out ASize: TFpDbgValueSize
890   ): Boolean;
891 var
892   t: TFpSymbol;
893 begin
894   t := FValue.TypeInfo;
895   if t <> nil then t := t.TypeInfo;
896   if t <> nil then
897     t.ReadSize(nil, ASize) // TODO: create a value object for the deref
898   else
899     Result := inherited DoGetSize(ASize);
900 end;
901 
TFpPasParserValueDerefPointer.GetAsCardinalnull902 function TFpPasParserValueDerefPointer.GetAsCardinal: QWord;
903 var
904   m: TFpDbgMemManager;
905   Addr: TFpDbgMemLocation;
906   Ctx: TFpDbgLocationContext;
907   AddrSize: Integer;
908 begin
909   Result := FCardinal;
910   if FCardinalRead then exit;
911 
912   Ctx := Context;
913   if Ctx = nil then exit;
914   AddrSize := Ctx.SizeOfAddress;
915   if (AddrSize <= 0) or (AddrSize > SizeOf(FCardinal)) then exit;
916   m := Ctx.MemManager;
917   if m = nil then exit;
918 
919   FCardinal := 0;
920   FCardinalRead := True;
921   Addr := GetAddress;
922   if not IsReadableLoc(Addr) then exit;
923   FCardinal := LocToAddrOrNil(Ctx.ReadAddress(Addr, SizeVal(Ctx.SizeOfAddress)));
924 
925   Result := FCardinal;
926 end;
927 
GetTypeInfonull928 function TFpPasParserValueDerefPointer.GetTypeInfo: TFpSymbol;
929 var
930   t: TFpSymbol;
931 begin
932   t := FValue.TypeInfo;
933   if t <> nil then t := t.TypeInfo;
934   if t <> nil then
935     Result := t
936   else
937     Result := inherited GetTypeInfo;
938 end;
939 
940 constructor TFpPasParserValueDerefPointer.Create(AValue: TFpValue;
941   AContext: TFpDbgLocationContext);
942 begin
943   Create(AValue, AContext, 0);
944 end;
945 
946 constructor TFpPasParserValueDerefPointer.Create(AValue: TFpValue;
947   AContext: TFpDbgLocationContext; AOffset: Int64);
948 begin
949   inherited Create(AContext);
950   FValue := AValue;
951   FValue.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FValue, 'TPasParserDerefPointerSymbolValue'){$ENDIF};
952   FAddressOffset := AOffset;
953 end;
954 
955 destructor TFpPasParserValueDerefPointer.Destroy;
956 begin
957   inherited Destroy;
958   FValue.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FValue, 'TPasParserDerefPointerSymbolValue'){$ENDIF};
959 end;
960 
961 { TPasParserAddressOfSymbolValue }
962 
TFpPasParserValueAddressOf.GetPointedToValuenull963 function TFpPasParserValueAddressOf.GetPointedToValue: TFpValue;
964 begin
965   Result := FValue;
966 end;
967 
DebugTextnull968 function TFpPasParserValueAddressOf.DebugText(AIndent: String): String;
969 begin
970   Result := inherited DebugText(AIndent)
971           + AIndent + '-Value= ' + DbgsResultValue(FValue, AIndent + '  ') + LineEnding
972           + AIndent + '-Symbol = ' + DbgsSymbol(FTypeInfo, AIndent + '  ') + LineEnding;
973 end;
974 
GetKindnull975 function TFpPasParserValueAddressOf.GetKind: TDbgSymbolKind;
976 begin
977   Result := skPointer;
978 end;
979 
TFpPasParserValueAddressOf.GetFieldFlagsnull980 function TFpPasParserValueAddressOf.GetFieldFlags: TFpValueFieldFlags;
981 begin
982     Result := [svfOrdinal, svfCardinal, svfSizeOfPointer, svfDataAddress];
983     if FValue.Kind in [skChar] then
984       Result := Result + FValue.FieldFlags * [svfString, svfWideString];
985 end;
986 
GetAsIntegernull987 function TFpPasParserValueAddressOf.GetAsInteger: Int64;
988 begin
989   Result := Int64(LocToAddrOrNil(FValue.Address));
990 end;
991 
TFpPasParserValueAddressOf.GetAsCardinalnull992 function TFpPasParserValueAddressOf.GetAsCardinal: QWord;
993 begin
994   Result := QWord(LocToAddrOrNil(FValue.Address));
995 end;
996 
GetTypeInfonull997 function TFpPasParserValueAddressOf.GetTypeInfo: TFpSymbol;
998 begin
999   Result := FTypeInfo;
1000   if Result <> nil then
1001     exit;
1002   if FValue.TypeInfo = nil then
1003     exit;
1004 
1005   FTypeInfo := TPasParserSymbolPointer.Create(FValue.TypeInfo, FContext);
1006   {$IFDEF WITH_REFCOUNT_DEBUG}FTypeInfo.DbgRenameReference(@FTypeInfo, 'TPasParserAddressOfSymbolValue');{$ENDIF}
1007   Result := FTypeInfo;
1008 end;
1009 
TFpPasParserValueAddressOf.GetDataAddressnull1010 function TFpPasParserValueAddressOf.GetDataAddress: TFpDbgMemLocation;
1011 begin
1012   Result := FValue.Address;
1013 end;
1014 
GetMembernull1015 function TFpPasParserValueAddressOf.GetMember(AIndex: Int64): TFpValue;
1016 var
1017   ti: TFpSymbol;
1018   addr: TFpDbgMemLocation;
1019   Tmp: TFpValueConstAddress;
1020   Size: TFpDbgValueSize;
1021 begin
1022   if (AIndex = 0) or (FValue = nil) then begin
1023     Result := FValue;
1024     if Result <> nil then
1025       Result.AddReference;
1026     exit;
1027   end;
1028 
1029   Result := nil;
1030   ti := FValue.TypeInfo;
1031   addr := FValue.Address;
1032   if not IsTargetAddr(addr) then begin
1033     //LastError := CreateError(fpErrAnyError, ['Internal dereference error']);
1034     exit;
1035   end;
1036   {$PUSH}{$R-}{$Q-} // TODO: check overflow
1037   if (ti <> nil) and (AIndex <> 0) then begin
1038     // Only test for hardcoded size. TODO: dwarf 3 could have variable size, but for char that is not expected
1039     // TODO: Size of member[0] ?
1040     if not ti.ReadSize(nil, Size) then begin
1041       SetLastError(CreateError(fpErrAnyError, ['Can index element of unknown size']));
1042       exit;
1043     end;
1044     AIndex := AIndex * SizeToFullBytes(Size);
1045   end;
1046   addr.Address := addr.Address + AIndex;
1047   {$POP}
1048 
1049   Tmp := TFpValueConstAddress.Create(addr);
1050   if ti <> nil then begin
1051     Result := ti.TypeCastValue(Tmp);
1052     if Result is TFpValueDwarfBase then
1053       TFpValueDwarfBase(Result).Context := Context;
1054     Tmp.ReleaseReference;
1055   end
1056   else
1057     Result := Tmp;
1058 end;
1059 
TFpPasParserValueAddressOf.GetAsStringnull1060 function TFpPasParserValueAddressOf.GetAsString: AnsiString;
1061 begin
1062   Result := FValue.AsString;
1063 end;
1064 
GetAsWideStringnull1065 function TFpPasParserValueAddressOf.GetAsWideString: WideString;
1066 begin
1067   Result := FValue.AsWideString;
1068 end;
1069 
1070 constructor TFpPasParserValueAddressOf.Create(AValue: TFpValue;
1071   AContext: TFpDbgLocationContext);
1072 begin
1073   inherited Create(AContext);
1074   FValue := AValue;
1075   FValue.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FValue, 'TPasParserAddressOfSymbolValue'){$ENDIF};
1076 end;
1077 
1078 destructor TFpPasParserValueAddressOf.Destroy;
1079 begin
1080   inherited Destroy;
1081   FValue.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FValue, 'TPasParserAddressOfSymbolValue'){$ENDIF};
1082   FTypeInfo.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FTypeInfo, 'TPasParserAddressOfSymbolValue'){$ENDIF};
1083 end;
1084 
1085 { TPasParserSymbolArrayDeIndex }
1086 
TPasParserSymbolArrayDeIndex.GetNestedSymbolCountnull1087 function TPasParserSymbolArrayDeIndex.GetNestedSymbolCount: Integer;
1088 begin
1089   Result := (inherited GetNestedSymbolCount) - 1;
1090 end;
1091 
TPasParserSymbolArrayDeIndex.GetNestedSymbolnull1092 function TPasParserSymbolArrayDeIndex.GetNestedSymbol(AIndex: Int64): TFpSymbol;
1093 begin
1094   Result := inherited GetNestedSymbol(AIndex + 1);
1095 end;
1096 
1097 constructor TPasParserSymbolArrayDeIndex.Create(const AnArray: TFpSymbol);
1098 begin
1099   FArray := AnArray;
1100   FArray.AddReference;
1101   inherited Create('');
1102   SetKind(skArray);
1103   SetForwardToSymbol(FArray);
1104 end;
1105 
1106 destructor TPasParserSymbolArrayDeIndex.Destroy;
1107 begin
1108   ReleaseRefAndNil(FArray);
1109   inherited Destroy;
1110 end;
1111 
1112 { TPasParserSymbolPointer }
1113 
1114 procedure TPasParserSymbolPointer.TypeInfoNeeded;
1115 var
1116   t: TPasParserSymbolPointer;
1117 begin
1118   if FPointerLevels = 0 then begin
1119     SetTypeInfo(FPointedTo);
1120     exit;
1121   end;
1122   assert(FPointerLevels > 1, 'TPasParserSymbolPointer.TypeInfoNeeded: FPointerLevels > 1');
1123   t := TPasParserSymbolPointer.Create(FPointedTo, FContext, FPointerLevels-1);
1124   SetTypeInfo(t);
1125   t.ReleaseReference;
1126 end;
1127 
DoReadSizenull1128 function TPasParserSymbolPointer.DoReadSize(const AValueObj: TFpValue; out
1129   ASize: TFpDbgValueSize): Boolean;
1130 begin
1131   ASize := SizeVal(FContext.SizeOfAddress);
1132   Result := True;
1133 end;
1134 
1135 constructor TPasParserSymbolPointer.Create(const APointedTo: TFpSymbol;
1136   AContext: TFpDbgLocationContext; APointerLevels: Integer);
1137 begin
1138   inherited Create('');
1139   FContext := AContext;
1140   FPointerLevels := APointerLevels;
1141   FPointedTo := APointedTo;
1142   FPointedTo.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(FPointedTo, 'TPasParserSymbolPointer'){$ENDIF};
1143   if APointerLevels = 1 then
1144     SetTypeInfo(APointedTo);
1145   SetKind(skPointer);
1146   SetSymbolType(stType);
1147 end;
1148 
1149 constructor TPasParserSymbolPointer.Create(const APointedTo: TFpSymbol;
1150   AContext: TFpDbgLocationContext);
1151 begin
1152   Create(APointedTo, AContext, 1);
1153 end;
1154 
1155 destructor TPasParserSymbolPointer.Destroy;
1156 begin
1157   FPointedTo.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(FPointedTo, 'TPasParserSymbolPointer'){$ENDIF};
1158   inherited Destroy;
1159 end;
1160 
TPasParserSymbolPointer.TypeCastValuenull1161 function TPasParserSymbolPointer.TypeCastValue(AValue: TFpValue): TFpValue;
1162 begin
1163   Result := TFpPasParserValueCastToPointer.Create(AValue, Self, FContext);
1164 end;
1165 
1166 
1167 { TFpPascalExpressionPartBracketIndex }
1168 
1169 procedure TFpPascalExpressionPartBracketIndex.Init;
1170 begin
1171   FPrecedence := PRECEDENCE_ARRAY_IDX;
1172   inherited Init;
1173 end;
1174 
DoGetResultValuenull1175 function TFpPascalExpressionPartBracketIndex.DoGetResultValue: TFpValue;
1176 var
1177   TmpVal, TmpVal2, TmpIndex: TFpValue;
1178   i: Integer;
1179   Offs: Int64;
1180   ti: TFpSymbol;
1181   IsPChar: Boolean;
1182   v: String;
1183   w: WideString;
1184 begin
1185   Result := nil;
1186   assert(Count >= 2, 'TFpPascalExpressionPartBracketIndex.DoGetResultValue: Count >= 2');
1187   if Count < 2 then exit;
1188 
1189   TmpVal := Items[0].ResultValue;
1190   if TmpVal = nil then exit;
1191 
1192   TmpVal.AddReference;
1193   for i := 1 to Count - 1 do begin
1194     TmpVal2 := nil;
1195     TmpIndex := Items[i].ResultValue;
1196     if TmpIndex = nil then begin
1197       // error should be set by Items[i]
1198       TmpVal.ReleaseReference;
1199       exit;
1200     end;
1201     case TmpVal.Kind of
1202       skArray: begin
1203           if (svfInteger in TmpIndex.FieldFlags) then
1204             TmpVal2 := TmpVal.Member[TmpIndex.AsInteger]
1205           else
1206           if (svfOrdinal in TmpIndex.FieldFlags) and
1207              (TmpIndex.AsCardinal <= high(Int64))
1208           then
1209             TmpVal2 := TmpVal.Member[TmpIndex.AsCardinal]
1210           else
1211           begin
1212             SetError('Can not calculate Index');
1213             TmpVal.ReleaseReference;
1214             exit;
1215           end;
1216         end; // Kind = skArray
1217       skPointer: begin
1218           if (svfInteger in TmpIndex.FieldFlags) then
1219             Offs := TmpIndex.AsInteger
1220           else
1221           if (svfOrdinal in TmpIndex.FieldFlags) and (TmpIndex.AsCardinal <= high(Int64))
1222           then
1223             Offs := Int64(TmpIndex.AsCardinal)
1224           else
1225           begin
1226             SetError('Can not calculate Index');
1227             TmpVal.ReleaseReference;
1228             exit;
1229           end;
1230 
1231           ti := TmpVal.TypeInfo;
1232           if (ti <> nil) then ti := ti.TypeInfo;
1233           IsPChar := (ti <> nil) and (ti.Kind in [skChar]) and (Offs > 0) and
1234                      (not(TmpVal is TFpPasParserValueAddressOf)) and
1235                      (not(TmpVal is TFpPasParserValueCastToPointer)) and
1236                      (not(TmpVal is TFpPasParserValueMakeReftype));
1237           if IsPChar then FExpression.FHasPCharIndexAccess := True;
1238           if IsPChar and FExpression.FixPCharIndexAccess then begin
1239             // fix for string in dwarf 2
1240             if Offs > 0 then
1241               dec(Offs);
1242           end;
1243 
1244           TmpVal2 := TmpVal.Member[Offs];
1245           if IsError(TmpVal.LastError) then
1246             SetError('Error dereferencing'); // TODO: set correct error
1247         end;
1248       skString, skAnsiString: begin
1249           //TODO: move to FpDwarfValue.member ??
1250           if (svfInteger in TmpIndex.FieldFlags) then
1251             Offs := TmpIndex.AsInteger
1252           else
1253           if (svfOrdinal in TmpIndex.FieldFlags) and (TmpIndex.AsCardinal <= high(Int64))
1254           then
1255             Offs := Int64(TmpIndex.AsCardinal)
1256           else
1257           begin
1258             SetError('Can not calculate Index');
1259             TmpVal.ReleaseReference;
1260             exit;
1261           end;
1262 
1263           v := TmpVal.AsString;
1264           if (Offs < 1) or (Offs > Length(v)) then begin
1265             SetError('Index out of range');
1266             TmpVal.ReleaseReference;
1267             exit;
1268           end;
1269 
1270           TmpVal2 := TFpValueConstChar.Create(v[Offs]);
1271         end;
1272       skWideString: begin
1273           //TODO: move to FpDwarfValue.member ??
1274           if (svfInteger in TmpIndex.FieldFlags) then
1275             Offs := TmpIndex.AsInteger
1276           else
1277           if (svfOrdinal in TmpIndex.FieldFlags) and (TmpIndex.AsCardinal <= high(Int64))
1278           then
1279             Offs := Int64(TmpIndex.AsCardinal)
1280           else
1281           begin
1282             SetError('Can not calculate Index');
1283             TmpVal.ReleaseReference;
1284             exit;
1285           end;
1286 
1287           w := TmpVal.AsWideString;
1288           if (Offs < 1) or (Offs > Length(w)) then begin
1289             SetError('Index out of range');
1290             TmpVal.ReleaseReference;
1291             exit;
1292           end;
1293 
1294           TmpVal2 := TFpValueConstChar.Create(w[Offs]);
1295         end;
1296       else
1297         begin
1298           SetError(fpErrTypeHasNoIndex, [GetText]);
1299           TmpVal.ReleaseReference;
1300           exit;
1301         end;
1302     end;
1303 
1304     TmpVal.ReleaseReference;
1305     if TmpVal2 = nil then begin
1306       SetError('Internal Error, attempting to read array element');
1307       exit;
1308     end;
1309     TmpVal := TmpVal2;
1310   end;
1311 
1312   Result := TmpVal;
1313   {$IFDEF WITH_REFCOUNT_DEBUG}if Result <> nil then Result.DbgRenameReference(nil, 'DoGetResultValue'){$ENDIF};
1314 end;
1315 
TFpPascalExpressionPartBracketIndex.IsValidAfterPartnull1316 function TFpPascalExpressionPartBracketIndex.IsValidAfterPart(APrevPart: TFpPascalExpressionPart): Boolean;
1317 begin
1318   Result := inherited IsValidAfterPart(APrevPart);
1319   Result := Result and APrevPart.CanHaveOperatorAsNext;
1320   if (APrevPart.Parent <> nil) and (APrevPart.Parent.HasPrecedence) then
1321     Result := False;
1322 end;
1323 
HandleNextPartInBracketnull1324 function TFpPascalExpressionPartBracketIndex.HandleNextPartInBracket(APart: TFpPascalExpressionPart): TFpPascalExpressionPart;
1325 begin
1326   Result := Self;
1327   if Count < 1 then begin // Todo a,b,c
1328     SetError(APart, 'Internal error handling [] '+GetText+': '); // Missing the array on which this index works
1329     APart.Free;
1330     exit;
1331   end;
1332   if (Count > 1) and (not AfterComma) then begin
1333     SetError(APart, 'Comma or closing "]" expected '+GetText+': ');
1334     APart.Free;
1335     exit;
1336   end;
1337   if not IsValidNextPart(APart) then begin
1338     SetError(APart, 'Invalid operand in [] '+GetText+': ');
1339     APart.Free;
1340     exit;
1341   end;
1342 
1343   Add(APart);
1344   Result := APart;
1345 end;
1346 
MaybeHandlePrevPartnull1347 function TFpPascalExpressionPartBracketIndex.MaybeHandlePrevPart(APrevPart: TFpPascalExpressionPart;
1348   var AResult: TFpPascalExpressionPart): Boolean;
1349 var
1350   ALeftSide: TFpPascalExpressionPart;
1351 begin
1352   //Result := MaybeAddLeftOperand(APrevPart, AResult);
1353 
1354   Result := APrevPart.IsValidNextPart(Self);
1355   if not Result then
1356     exit;
1357 
1358   AResult := Self;
typenull1359   if (Count > 0)  // function/type already set
1360   then begin
1361     SetError(APrevPart, 'Parse error in () '+GetText+': ');
1362     APrevPart.Free;
1363     exit;
1364   end;
1365 
1366   ALeftSide := APrevPart.FindLeftSideOperandByPrecedence(Self);
1367   if ALeftSide = nil then begin
1368     SetError(Self, 'Internal parser error for operator '+GetText+': ');
1369     APrevPart.Free;
1370     exit;
1371   end;
1372 
1373   ALeftSide.ReplaceInParent(Self);
1374   Add(ALeftSide);
1375 end;
1376 
1377 procedure TFpPascalExpressionPartBracketIndex.DoHandleEndOfExpression;
1378 begin
1379   inherited DoHandleEndOfExpression;
1380   if (Count < 2) then
1381     SetError(fpErrPasParserMissingIndexExpression, [GetText]);
1382 end;
1383 
TFpPascalExpressionPartBracketIndex.HandleSeparatornull1384 function TFpPascalExpressionPartBracketIndex.HandleSeparator(ASeparatorType: TSeparatorType): Boolean;
1385 begin
1386   if (not (ASeparatorType = ppstComma)) or IsClosed then begin
1387     Result := inherited HandleSeparator(ASeparatorType);
1388     exit;
1389   end;
1390 
1391   Result := (Count > FAfterComma) and (Count > 1); // First element is name of array (in front of "[")
1392   if Result then
1393     SetAfterCommaFlag;
1394 end;
1395 
1396 { TFpPascalExpressionPartBracketSet }
1397 
HandleNextPartInBracketnull1398 function TFpPascalExpressionPartBracketSet.HandleNextPartInBracket(APart: TFpPascalExpressionPart): TFpPascalExpressionPart;
1399 begin
1400   Result := Self;
1401   if (Count > 0) and (not AfterComma) then begin
1402     SetError('To many expressions'); // TODO comma
1403     APart.Free;
1404     exit;
1405   end;
1406 
1407   Result := APart;
1408   Add(APart);
1409 end;
1410 
TFpPascalExpressionPartBracketSet.HandleSeparatornull1411 function TFpPascalExpressionPartBracketSet.HandleSeparator(ASeparatorType: TSeparatorType): Boolean;
1412 begin
1413   if (not (ASeparatorType = ppstComma)) or IsClosed then begin
1414     Result := inherited HandleSeparator(ASeparatorType);
1415     exit;
1416   end;
1417 
1418   Result := (Count > FAfterComma) and (Count > 0);
1419   if Result then
1420     SetAfterCommaFlag;
1421 end;
1422 
1423 { TFpPascalExpressionPartWithPrecedence }
1424 
TFpPascalExpressionPartWithPrecedence.HasPrecedencenull1425 function TFpPascalExpressionPartWithPrecedence.HasPrecedence: Boolean;
1426 begin
1427   Result := True;
1428 end;
1429 
1430 
1431 { TFpPascalExpressionPartBracketArgumentList }
1432 
1433 procedure TFpPascalExpressionPartBracketArgumentList.Init;
1434 begin
1435   FPrecedence := PRECEDENCE_ARG_LIST;
1436   inherited Init;
1437 end;
1438 
TFpPascalExpressionPartBracketArgumentList.DoGetResultValuenull1439 function TFpPascalExpressionPartBracketArgumentList.DoGetResultValue: TFpValue;
1440 var
1441   tmp, tmp2, tmpSelf: TFpValue;
1442   err: TFpError;
1443   Itm0: TFpPascalExpressionPart;
1444   ItmMO: TFpPascalExpressionPartOperatorMemberOf absolute Itm0;
1445   Params: TFpPascalExpressionPartListForwarder;
1446 begin
1447   Result := nil;
1448 
1449   if (Count = 0) then begin
1450     SetError(fpErrPasParserInvalidExpression, []);
1451     exit;
1452   end;
1453 
1454   Itm0 := Items[0];
1455   tmp := Itm0.ResultValue;
1456   if (tmp = nil) or (not Expression.Valid) then
1457     exit;
1458 
thennull1459   if (tmp.DbgSymbol <> nil) and (tmp.DbgSymbol.Kind = skFunction) then begin
1460     if not Assigned(Expression.OnFunctionCall) then begin
1461       SetError('calling functions not allowed');
1462       exit;
1463     end;
1464 
1465     tmpSelf := nil;
1466     if (Itm0 is TFpPascalExpressionPartOperatorMemberOf) then begin
1467       if ItmMO.Count = 2 then
1468         tmpSelf := ItmMO.Items[0].ResultValue;
1469       if tmpSelf = nil then begin
1470         SetError('internal error evaluating method call');
1471         exit;
1472       end;
1473     end;
1474 
1475     err := NoError;
1476     Params := TFpPascalExpressionPartListForwarder.Create(Self, 1, Count - 1);
1477     try
1478       if not Expression.OnFunctionCall(Self, tmp, tmpSelf, Params, Result, err) then begin
1479         if not IsError(err) then
1480           SetError('unknown error calling function')
1481         else
1482           Expression.SetError(err);
1483         Result := nil;
1484       end;
1485     finally
1486       Params.Free;
1487     end;
1488     {$IFDEF WITH_REFCOUNT_DEBUG}if Result <> nil then Result.DbgRenameReference(nil, 'DoGetResultValue'){$ENDIF};
1489 
1490     exit;
1491   end;
1492 
1493   if (Count = 2) then begin
1494     //TODO if tmp is TFpPascalExpressionPartOperatorMakeRef then
1495     //     AVOID creating the TPasParserSymbolPointer by calling tmp.DbgSymbol
1496     //     it ran be created in TPasParserSymbolValueCastToPointer if needed.
1497     if (tmp <> nil) and (tmp.DbgSymbol <> nil) and
1498        (tmp.DbgSymbol.SymbolType = stType)
1499     then begin
1500       // This is a typecast
1501       tmp2 := Items[1].ResultValue;
1502       if tmp2 <> nil then
1503         Result := tmp.GetTypeCastedValue(tmp2);
1504         //Result := tmp.DbgSymbol.TypeCastValue(tmp2);
1505       if Result <> nil then
1506         {$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue'){$ENDIF};
1507 
1508       exit;
1509     end;
1510   end;
1511 
callnull1512   // Must be function call // skProcedure is not handled
1513   SetError('unknown type or function');
1514 end;
1515 
DoGetIsTypeCastnull1516 function TFpPascalExpressionPartBracketArgumentList.DoGetIsTypeCast: Boolean;
1517 begin
1518   Result := False;
1519 end;
1520 
TFpPascalExpressionPartBracketArgumentList.IsValidAfterPartnull1521 function TFpPascalExpressionPartBracketArgumentList.IsValidAfterPart(APrevPart: TFpPascalExpressionPart): Boolean;
1522 begin
1523   Result := inherited IsValidAfterPart(APrevPart);
1524   Result := Result and APrevPart.CanHaveOperatorAsNext;
1525   if (APrevPart.Parent <> nil) and (APrevPart.Parent.HasPrecedence) then
1526     Result := False;
1527 end;
1528 
HandleNextPartInBracketnull1529 function TFpPascalExpressionPartBracketArgumentList.HandleNextPartInBracket(APart: TFpPascalExpressionPart): TFpPascalExpressionPart;
1530 begin
1531   Result := Self;
1532   if Count < 1 then begin // Todo a,b,c
1533     SetError(APart, 'Internal error handling () '+GetText+': '); // Missing the functionname on which this index works
1534     APart.Free;
1535     exit;
1536   end;
1537   if (Count > 1) and (not AfterComma) then begin // Todo a,b,c
1538     SetError(APart, 'Comma or closing ")" expected: '+GetText+': ');
1539     APart.Free;
1540     exit;
1541   end;
1542   if not IsValidNextPart(APart) then begin
1543     SetError(APart, 'Invalid operand in () '+GetText+': ');
1544     APart.Free;
1545     exit;
1546   end;
1547 
1548   Add(APart);
1549   Result := APart;
1550 end;
1551 
MaybeHandlePrevPartnull1552 function TFpPascalExpressionPartBracketArgumentList.MaybeHandlePrevPart(APrevPart: TFpPascalExpressionPart;
1553   var AResult: TFpPascalExpressionPart): Boolean;
1554 var
1555   ALeftSide: TFpPascalExpressionPart;
1556 begin
1557   //Result := MaybeAddLeftOperand(APrevPart, AResult);
1558 
1559   Result := APrevPart.IsValidNextPart(Self);
1560   if not Result then
1561     exit;
1562 
1563   AResult := Self;
typenull1564   if (Count > 0)  // function/type already set
1565   then begin
1566     SetError(APrevPart, 'Parse error in () '+GetText+': ');
1567     APrevPart.Free;
1568     exit;
1569   end;
1570 
1571   ALeftSide := APrevPart.FindLeftSideOperandByPrecedence(Self);
1572   if ALeftSide = nil then begin
1573     SetError(Self, 'Internal parser error for operator '+GetText+': ');
1574     APrevPart.Free;
1575     exit;
1576   end;
1577 
1578   ALeftSide.ReplaceInParent(Self);
1579   Add(ALeftSide);
1580 end;
1581 
HandleSeparatornull1582 function TFpPascalExpressionPartBracketArgumentList.HandleSeparator(ASeparatorType: TSeparatorType): Boolean;
1583 begin
1584   if (not (ASeparatorType = ppstComma)) or IsClosed then begin
1585     Result := inherited HandleSeparator(ASeparatorType);
1586     exit;
1587   end;
1588 
1589   Result := (Count > FAfterComma) and (Count > 1); // First element is name of function (in front of "(")
1590   if Result then
1591     SetAfterCommaFlag;
1592 end;
1593 
1594 { TFpPascalExpressionPartBracketSubExpression }
1595 
HandleNextPartInBracketnull1596 function TFpPascalExpressionPartBracketSubExpression.HandleNextPartInBracket(APart: TFpPascalExpressionPart): TFpPascalExpressionPart;
1597 begin
1598   Result := Self;
1599   if Count > 0 then begin
1600     SetError('To many expressions');
1601     APart.Free;
1602     exit;
1603   end;
1604 
1605   Result := APart;
1606   Add(APart);
1607 end;
1608 
TFpPascalExpressionPartBracketSubExpression.DoGetResultValuenull1609 function TFpPascalExpressionPartBracketSubExpression.DoGetResultValue: TFpValue;
1610 begin
1611   if Count <> 1 then
1612     Result := nil
1613   else
1614     Result := Items[0].ResultValue;
1615   if Result <> nil then
1616     Result.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(nil, 'DoGetResultValue'){$ENDIF};
1617 end;
1618 
1619 { TFpPascalExpressionPartIdentifier }
1620 
TFpPascalExpressionPartIdentifier.DoGetIsTypeCastnull1621 function TFpPascalExpressionPartIdentifier.DoGetIsTypeCast: Boolean;
1622 begin
1623   Result := (ResultValue <> nil) and (ResultValue.DbgSymbol <> nil) and (ResultValue.DbgSymbol.SymbolType = stType);
1624 end;
1625 
TFpPascalExpressionPartIdentifier.DoGetResultValuenull1626 function TFpPascalExpressionPartIdentifier.DoGetResultValue: TFpValue;
1627 var
1628   s: String;
1629   tmp: TFpValueConstAddress;
1630 begin
1631   s := GetText;
1632   Result := FExpression.GetDbgSymbolForIdentifier(s);
1633   if Result = nil then begin
1634     if CompareText(s, 'nil') = 0 then begin
1635       tmp := TFpValueConstAddress.Create(NilLoc);
1636       Result := TFpPasParserValueAddressOf.Create(tmp, Expression.Context.LocationContext);
1637       tmp.ReleaseReference;
1638       {$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue');{$ENDIF}
1639     end
1640     else
1641     if CompareText(s, 'true') = 0 then begin
1642       Result := TFpValueConstBool.Create(True);
1643       {$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue');{$ENDIF}
1644     end
1645     else
1646     if CompareText(s, 'false') = 0 then begin
1647       Result := TFpValueConstBool.Create(False);
1648       {$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue');{$ENDIF}
1649     end
1650     else begin
1651       SetError(fpErrSymbolNotFound, [GetText]);
1652       exit;
1653     end;
1654   end
1655 {$IFDEF WITH_REFCOUNT_DEBUG}
1656   else
1657     Result.DbgRenameReference(nil, 'DoGetResultValue')
1658 {$ENDIF}
1659   ;
1660 end;
1661 
GetFirstTokennull1662 function GetFirstToken(AText: PChar): String;
1663 begin
1664   Result := AText[0];
1665   if AText^ in ['a'..'z', 'A'..'Z', '_', '0'..'9'] then begin
1666     inc(AText);
1667     while (AText^ in ['a'..'z', 'A'..'Z', '_', '0'..'9']) and (Length(Result) < 200) do begin
1668       Result := Result + AText[0];
1669       inc(AText);
1670     end;
1671   end
1672   else
1673   begin
1674     inc(AText);
1675     while not (AText^ in [#0..#32, 'a'..'z', 'A'..'Z', '_', '0'..'9']) and (Length(Result) < 100) do begin
1676       Result := Result + AText[0];
1677       inc(AText);
1678     end;
1679   end;
1680 end;
1681 
1682 { TFpPascalExpressionPartConstantNumber }
1683 
TFpPascalExpressionPartConstantNumber.DoGetResultValuenull1684 function TFpPascalExpressionPartConstantNumber.DoGetResultValue: TFpValue;
1685 var
1686   i: QWord;
1687   e: word;
1688 begin
1689   Val(GetText, i, e);
1690   if e <> 0 then begin
1691     Result := nil;
1692     SetError(fpErrInvalidNumber, [GetText]);
1693     exit;
1694   end;
1695 
1696   if FStartChar^ in ['0'..'9'] then
1697     Result := TFpValueConstNumber.Create(i, False)
1698   else
1699     Result := TFpValueConstNumber.Create(Int64(i), True); // hex,oct,bin values default to signed
1700   {$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue'){$ENDIF};
1701 end;
1702 
1703 { TFpPascalExpressionPartConstantNumberFloat }
1704 
TFpPascalExpressionPartConstantNumberFloat.DoGetResultValuenull1705 function TFpPascalExpressionPartConstantNumberFloat.DoGetResultValue: TFpValue;
1706 var
1707   f: Extended;
1708   s: String;
1709 begin
1710   s := GetText;
1711   if not TextToFloat(PChar(s), f) then begin
1712     Result := nil;
1713     SetError(fpErrInvalidNumber, [GetText]);
1714     exit;
1715   end;
1716 
1717   Result := TFpValueConstFloat.Create(f);
1718   {$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue'){$ENDIF};
1719 end;
1720 
1721 { TFpPascalExpressionPartConstantText }
1722 
TFpPascalExpressionPartConstantText.DoGetResultValuenull1723 function TFpPascalExpressionPartConstantText.DoGetResultValue: TFpValue;
1724 begin
1725   //s := GetText;
1726   Result := TFpValueConstString.Create(FValue);
1727   {$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue'){$ENDIF};
1728 end;
1729 
CheckTokennull1730 function CheckToken(const tk: String; CurPtr: PChar): boolean; inline;
1731 var
1732   p, t: PChar;
1733   l: Integer;
1734 begin
1735   Result := False;
1736   l := Length(tk);
1737   p := CurPtr + l;
1738   t := @tk[l];
1739   while p > CurPtr do begin
1740     if chr(ord(p^) and $DF) <> t^ then
1741       exit;
1742     dec(p);
1743     dec(t);
1744   end;
1745   Result := True;
1746 end;
1747 { TFpPascalExpression }
1748 
1749 procedure TFpPascalExpression.Parse;
1750 var
1751   CurPtr, EndPtr, TokenEndPtr: PChar;
1752   CurPart, NewPart: TFpPascalExpressionPart;
1753 
1754   procedure AddPart(AClass: TFpPascalExpressionPartClass);
1755   begin
1756     NewPart := AClass.Create(Self, CurPtr, TokenEndPtr-1);
1757   end;
1758 
1759   procedure AddPlusMinus;
1760   begin
1761     if (CurPart = nil) or (not CurPart.CanHaveOperatorAsNext)
1762     then AddPart(TFpPascalExpressionPartOperatorUnaryPlusMinus)
1763     else AddPart(TFpPascalExpressionPartOperatorPlusMinus);
1764   end;
1765 
1766   procedure AddIdentifier;
1767   begin
1768     while TokenEndPtr^ in ['a'..'z', 'A'..'Z', '_', '0'..'9'] do
1769       inc(TokenEndPtr);
1770     // TODO: Check functions not, and, in, as, is ...
1771     if (CurPart <> nil) and (CurPart.CanHaveOperatorAsNext) then
1772     case TokenEndPtr - CurPtr of
1773       3: case chr(ord(CurPtr^) AND $DF) of
1774           'D': if CheckToken('IV', CurPtr) then
1775               NewPart := TFpPascalExpressionPartOperatorMulDiv.Create(Self, CurPtr, TokenEndPtr-1);
1776           'M': if CheckToken('OD', CurPtr) then
1777               NewPart := TFpPascalExpressionPartOperatorMulDiv.Create(Self, CurPtr, TokenEndPtr-1);
1778           'A': if CheckToken('ND', CurPtr) then
1779               NewPart := TFpPascalExpressionPartOperatorAnd.Create(Self, CurPtr, TokenEndPtr-1);
1780           'X': if CheckToken('OR', CurPtr) then
1781               NewPart := TFpPascalExpressionPartOperatorOr.Create(Self, ootXor, CurPtr, TokenEndPtr-1);
1782           'N': if CheckToken('OT', CurPtr) then
1783               NewPart := TFpPascalExpressionPartOperatorUnaryNot.Create(Self, CurPtr, TokenEndPtr-1);
1784         end;
1785       2: case chr(ord(CurPtr^) AND $DF) of
1786           'O': if CheckToken('R', CurPtr) then
1787               NewPart := TFpPascalExpressionPartOperatorOr.Create(Self, ootOr, CurPtr, TokenEndPtr-1);
1788         end;
1789     end
1790     else
1791     case TokenEndPtr - CurPtr of
1792       3: case chr(ord(CurPtr^) AND $DF) of
1793           'N': if CheckToken('OT', CurPtr) then
1794               NewPart := TFpPascalExpressionPartOperatorUnaryNot.Create(Self, CurPtr, TokenEndPtr-1);
1795         end;
1796     end;
1797     if NewPart = nil then
1798       NewPart := TFpPascalExpressionPartIdentifier.Create(Self, CurPtr, TokenEndPtr-1);
1799   end;
1800 
1801   procedure HandleDot;
1802   begin
1803     while TokenEndPtr^ = '.' do
1804       inc(TokenEndPtr);
1805     case TokenEndPtr - CurPtr of
1806       1: AddPart(TFpPascalExpressionPartOperatorMemberOf);
1807       //2: ; // ".."
1808       else SetError('Failed parsing ...');
1809     end;
1810   end;
1811 
1812   procedure AddRefOperator;
1813   begin
1814     if (CurPart = nil) or (not CurPart.CanHaveOperatorAsNext)
1815     then AddPart(TFpPascalExpressionPartOperatorMakeRef)
1816     else AddPart(TFpPascalExpressionPartOperatorDeRef);
1817   end;
1818 
1819   procedure HandleRoundBracket;
1820   begin
1821     if (CurPart = nil) or (not CurPart.CanHaveOperatorAsNext)
1822     then AddPart(TFpPascalExpressionPartBracketSubExpression)
1823     else AddPart(TFpPascalExpressionPartBracketArgumentList);
1824   end;
1825 
1826   procedure HandleSqareBracket;
1827   begin
1828     if (CurPart = nil) or (not CurPart.CanHaveOperatorAsNext)
1829     then AddPart(TFpPascalExpressionPartBracketSet)
1830     else AddPart(TFpPascalExpressionPartBracketIndex);
1831   end;
1832 
1833   procedure CloseBracket(ABracketClass: TFpPascalExpressionPartBracketClass);
1834   var
1835     BracketPart: TFpPascalExpressionPartBracket;
1836   begin
1837     BracketPart := CurPart.SurroundingBracket;
1838     if BracketPart = nil then begin
1839       SetError('Closing bracket found without opening')
1840     end
1841     else
1842     if not (BracketPart is ABracketClass) then begin
1843       SetError('Mismatch bracket')
1844     end
1845     else begin
1846       TFpPascalExpressionPartBracket(BracketPart).CloseBracket;
1847       CurPart := BracketPart;
1848     end;
1849   end;
1850 
1851   procedure AddConstNumber;
1852   begin
1853     case CurPtr^ of
1854       '$': while TokenEndPtr^ in ['a'..'f', 'A'..'F', '0'..'9'] do inc(TokenEndPtr);
1855       '&': if TokenEndPtr^ in ['a'..'z', 'A'..'Z'] then begin
1856              // escaped keyword used as identifier
1857              while TokenEndPtr^ in ['a'..'z', 'A'..'Z', '0'..'9', '_'] do inc(TokenEndPtr);
1858              NewPart := TFpPascalExpressionPartIdentifier.Create(Self, CurPtr, TokenEndPtr-1);
1859              exit;
1860            end
1861            else
1862             while TokenEndPtr^ in ['0'..'7'] do inc(TokenEndPtr);
1863       '%': while TokenEndPtr^ in ['0'..'1'] do inc(TokenEndPtr);
1864       '0'..'9':
1865         if (CurPtr^ = '0') and ((CurPtr + 1)^ in ['x', 'X']) and
1866            ((CurPtr + 2)^ in ['a'..'z', 'A'..'Z', '0'..'9'])
1867         then begin
1868           inc(TokenEndPtr, 2);
1869           while TokenEndPtr^ in ['a'..'z', 'A'..'Z', '0'..'9'] do inc(TokenEndPtr);
1870         end
1871         else begin
1872           while TokenEndPtr^ in ['0'..'9'] do inc(TokenEndPtr);
1873           // identify "2.", but not "[2..3]"  // CurExpr.IsFloatAllowed
1874           if (TokenEndPtr^ = DecimalSeparator) and (TokenEndPtr[1] <> '.') then begin
1875             inc(TokenEndPtr);
1876             while TokenEndPtr^ in ['0'..'9'] do inc(TokenEndPtr);
1877             if TokenEndPtr^ in ['a'..'z', 'A'..'Z', '_'] then
1878               SetError(fpErrPasParserUnexpectedToken, [GetFirstToken(CurPtr), PosFromPChar(CurPtr)])
1879             else
1880               AddPart(TFpPascalExpressionPartConstantNumberFloat);
1881             exit;
1882           end;
1883         end;
1884     end;
1885     if TokenEndPtr^ in ['a'..'z', 'A'..'Z', '_'] then
1886       SetError(fpErrPasParserUnexpectedToken, [GetFirstToken(CurPtr), PosFromPChar(CurPtr)])
1887     else
1888       AddPart(TFpPascalExpressionPartConstantNumber);
1889   end;
1890 
1891   procedure HandleCompare;
1892   begin
1893     if (CurPtr^ = '<') and (TokenEndPtr^ in ['>', '=']) then
1894       inc(TokenEndPtr);
1895     if (CurPtr^ = '>') and (TokenEndPtr^ in ['<', '=']) then
1896       inc(TokenEndPtr);
1897     AddPart(TFpPascalExpressionPartOperatorCompare);
1898   end;
1899 
1900   procedure HandleComma;
1901   begin
1902     if not CurPart.HandleSeparator(ppstComma) then
1903       SetError(fpErrPasParserUnexpectedToken, [GetFirstToken(CurPtr), PosFromPChar(CurPtr)]);
1904   end;
1905 
1906   procedure AddConstChar;
1907   var
1908     str: string;
1909     p: PChar;
1910     c: LongInt;
1911     WasQuote: Boolean;
1912   begin
1913     dec(TokenEndPtr);
1914     str := '';
1915     WasQuote := False;
1916     while (TokenEndPtr < EndPtr) and FValid do begin
1917       case TokenEndPtr^ of
1918         '''': begin
1919             if WasQuote then
1920               str := str + '''';
1921             WasQuote := False;
1922             inc(TokenEndPtr);
1923             p := TokenEndPtr;
1924             while (TokenEndPtr < EndPtr) and (TokenEndPtr^ <> '''') do
1925               inc(TokenEndPtr);
1926             str := str + copy(p, 1, TokenEndPtr - p);
1927             if (TokenEndPtr < EndPtr) and (TokenEndPtr^ = '''') then
1928               inc(TokenEndPtr)
1929             else
1930               SetError(fpErrPasParserInvalidExpression, []); // unterminated string
1931           end;
1932         '#': begin
1933             WasQuote := False;
1934             inc(TokenEndPtr);
1935             if not (TokenEndPtr < EndPtr) then
1936               SetError(fpErrPasParserInvalidExpression, []);
1937             p := TokenEndPtr;
1938             case TokenEndPtr^  of
1939               '$': begin
1940                   inc(TokenEndPtr);
1941                   if (not (TokenEndPtr < EndPtr)) or (not (TokenEndPtr^ in ['0'..'9', 'a'..'f', 'A'..'F'])) then
1942                     SetError(fpErrPasParserInvalidExpression, []);
1943                   while (TokenEndPtr < EndPtr) and (TokenEndPtr^ in ['0'..'9', 'a'..'f', 'A'..'F']) do
1944                     inc(TokenEndPtr);
1945                 end;
1946               '&': begin
1947                   inc(TokenEndPtr);
1948                   if (not (TokenEndPtr < EndPtr)) or (not (TokenEndPtr^ in ['0'..'7'])) then
1949                     SetError(fpErrPasParserInvalidExpression, []);
1950                   while (TokenEndPtr < EndPtr) and (TokenEndPtr^ in ['0'..'7']) do
1951                     inc(TokenEndPtr);
1952                 end;
1953               '%': begin
1954                   inc(TokenEndPtr);
1955                   if (not (TokenEndPtr < EndPtr)) or (not (TokenEndPtr^ in ['0'..'1'])) then
1956                     SetError(fpErrPasParserInvalidExpression, []);
1957                   while (TokenEndPtr < EndPtr) and (TokenEndPtr^ in ['0'..'1']) do
1958                     inc(TokenEndPtr);
1959                 end;
1960               '0'..'9': begin
1961                   while (TokenEndPtr < EndPtr) and (TokenEndPtr^ in ['0'..'9']) do
1962                     inc(TokenEndPtr);
1963                 end;
1964             end;
1965             c := StrToIntDef(copy(p , 1 , TokenEndPtr - p), -1);
1966             if c < 0 then
1967               SetError(fpErrPasParserInvalidExpression, []); // should not happen
1968             if c > 255 then // todo: need wide handling
1969               str := str + WideChar(c)
1970             else
1971               str := str + Char(c);
1972           end;
1973         ' ', #9, #10, #13:
1974           inc(TokenEndPtr);
1975         else
1976           break;
1977       end;
1978     end;
1979     if not FValid then
1980       exit;
1981     // If Length(str) = 1 then // char
1982     AddPart(TFpPascalExpressionPartConstantText);
1983     TFpPascalExpressionPartConstantText(NewPart).FValue := str;
1984   end;
1985 
1986 begin
1987   if FTextExpression = '' then
1988     exit;
1989   CurPtr := @FTextExpression[1];
1990   EndPtr := CurPtr + length(FTextExpression);
1991   CurPart := nil;
1992 
1993   While (CurPtr < EndPtr) and FValid do begin
1994     if CurPtr^ in [' ', #9, #10, #13] then begin
1995       while (CurPtr^ in [' ', #9, #10, #13]) and (CurPtr < EndPtr) do
1996         Inc(CurPtr);
1997       continue;
1998     end;
1999 
2000     NewPart := nil;
2001     TokenEndPtr := CurPtr + 1;
2002     case CurPtr^ of
2003       '@' :      AddPart(TFpPascalExpressionPartOperatorAddressOf);
2004       '^':       AddRefOperator; // ^A may be #$01
2005       '.':       HandleDot;
2006       '+', '-' : AddPlusMinus;
2007       '*', '/' : AddPart(TFpPascalExpressionPartOperatorMulDiv);
2008       '(':       HandleRoundBracket;
2009       ')':       CloseBracket(TFpPascalExpressionPartRoundBracket);
2010       '[':       HandleSqareBracket;
2011       ']':       CloseBracket(TFpPascalExpressionPartSquareBracket);
2012       ',':       HandleComma;
2013       '=', '<',
2014       '>':       HandleCompare;//TFpPascalExpressionPartOperatorCompare
2015       '''', '#': AddConstChar;
2016       '0'..'9',
2017       '$', '%', '&':  AddConstNumber;
2018       'a'..'z',
2019       'A'..'Z', '_': AddIdentifier;
2020       else begin
2021           //SetError(fpErrPasParserUnexpectedToken, [GetFirstToken(CurPtr), PosFromPChar(CurPtr)])
2022           SetError(Format('Unexpected token ''%0:s'' at pos %1:d', [CurPtr^, PosFromPChar(CurPtr)])); // error
2023           break;
2024         end;
2025     end;
2026     if not FValid then
2027       break;
2028 
2029     if CurPart = nil then
2030       CurPart := NewPart
2031     else
2032     if NewPart <> nil then
2033       CurPart := CurPart.HandleNextPart(NewPart);
2034 
2035     CurPtr :=  TokenEndPtr;
2036   end; // While CurPtr < EndPtr do begin
2037 
2038 
2039 
2040   if Valid then begin
2041     if CurPart <> nil then begin
2042       CurPart.HandleEndOfExpression;
2043       CurPart := CurPart.TopParent;
2044     end
2045     else
2046       SetError('No Expression');
2047   end
2048   else
2049   if CurPart <> nil then
2050     CurPart := CurPart.TopParent;
2051 
2052   FExpressionPart := CurPart;
2053 end;
2054 
TFpPascalExpression.GetResultValuenull2055 function TFpPascalExpression.GetResultValue: TFpValue;
2056 begin
2057   if (FExpressionPart = nil) or (not Valid) then
2058     Result := nil
2059   else begin
2060     Result := FExpressionPart.ResultValue;
2061     if (Result = nil) and (not IsError(FError)) then
2062       SetError(fpErrAnyError, ['Internal eval error']);
2063   end;
2064 end;
2065 
GetValidnull2066 function TFpPascalExpression.GetValid: Boolean;
2067 begin
2068   Result := FValid and (not IsError(FError));
2069 end;
2070 
2071 procedure TFpPascalExpression.SetError(AMsg: String);
2072 begin
2073   if IsError(FError) then begin
2074 DebugLn(['Skipping error ', AMsg]);
2075     FValid := False;
2076     exit;
2077   end;
2078   SetError(fpErrAnyError, [AMsg]);
2079 DebugLn(['PARSER ERROR ', AMsg]);
2080 end;
2081 
2082 procedure TFpPascalExpression.SetError(AnErrorCode: TFpErrorCode; AData: array of const);
2083 begin
2084   FValid := False;
2085   FError := ErrorHandler.CreateError(AnErrorCode, AData);
2086   DebugLn(['Setting error ', ErrorHandler.ErrorAsString(FError)]);
2087 end;
2088 
2089 procedure TFpPascalExpression.SetError(const AnErr: TFpError);
2090 begin
2091   FValid := False;
2092   FError := AnErr;
2093   DebugLn(['Setting error ', ErrorHandler.ErrorAsString(FError)]);
2094 end;
2095 
PosFromPCharnull2096 function TFpPascalExpression.PosFromPChar(APChar: PChar): Integer;
2097 begin
2098   Result := APChar - @FTextExpression[1] + 1;
2099 end;
2100 
TFpPascalExpression.GetDbgSymbolForIdentifiernull2101 function TFpPascalExpression.GetDbgSymbolForIdentifier(AnIdent: String): TFpValue;
2102 begin
2103   if FContext <> nil then
2104     Result := FContext.FindSymbol(AnIdent)
2105   else
2106     Result := nil;
2107 end;
2108 
2109 constructor TFpPascalExpression.Create(ATextExpression: String;
2110   AContext: TFpDbgSymbolScope);
2111 begin
2112   FContext := AContext;
2113   FContext.AddReference;
2114   FTextExpression := ATextExpression;
2115   FError := NoError;
2116   FValid := True;
2117   Parse;
2118 end;
2119 
2120 destructor TFpPascalExpression.Destroy;
2121 begin
2122   FreeAndNil(FExpressionPart);
2123   FContext.ReleaseReference;
2124   inherited Destroy;
2125 end;
2126 
TFpPascalExpression.DebugDumpnull2127 function TFpPascalExpression.DebugDump(AWithResults: Boolean): String;
2128 begin
2129   Result := 'TFpPascalExpression: ' + FTextExpression + LineEnding +
2130             'Valid: ' + dbgs(FValid) + '   Error: "' + dbgs(ErrorCode(FError)) + '"'+ LineEnding
2131             ;
2132   if FExpressionPart <> nil then
2133     Result := Result + FExpressionPart.DebugDump('  ', AWithResults);
2134   if AWithResults and (ResultValue <> nil) then
2135     if (ResultValue is TFpPasParserValue) then
2136       Result := Result + 'ResultValue = ' + LineEnding + TFpPasParserValue(ResultValue).DebugText('  ')
2137     else
2138       Result := Result + 'ResultValue = ' + LineEnding + DbgSName(ResultValue) + LineEnding ;
2139 end;
2140 
2141 procedure TFpPascalExpression.ResetEvaluation;
2142 begin
2143   FExpressionPart.ResetEvaluation;
2144 end;
2145 
2146 { TFpPascalExpressionPart }
2147 
2148 procedure TFpPascalExpressionPart.SetEndChar(AValue: PChar);
2149 begin
2150   if FEndChar = AValue then Exit;
2151   FEndChar := AValue;
2152 end;
2153 
TFpPascalExpressionPart.GetTopParentnull2154 function TFpPascalExpressionPart.GetTopParent: TFpPascalExpressionPart;
2155 begin
2156   Result := Self;
2157   while Result.Parent <> nil do
2158     Result := Result.Parent;
2159 end;
2160 
GetSurroundingOpenBracketnull2161 function TFpPascalExpressionPart.GetSurroundingOpenBracket: TFpPascalExpressionPartBracket;
2162 var
2163   tmp: TFpPascalExpressionPart;
2164 begin
2165   Result := nil;
2166   tmp := Self;
2167   while (tmp <> nil) and
2168         ( not(tmp is TFpPascalExpressionPartBracket) or ((tmp as TFpPascalExpressionPartBracket).IsClosed) )
2169   do
2170     tmp := tmp.Parent;
2171   if tmp <> nil then
2172     Result := TFpPascalExpressionPartBracket(tmp);
2173 end;
2174 
TFpPascalExpressionPart.GetResultValuenull2175 function TFpPascalExpressionPart.GetResultValue: TFpValue;
2176 begin
2177   Result := FResultValue;
2178   if FResultValDone then
2179     exit;
2180   FResultValue := DoGetResultValue;
2181   {$IFDEF WITH_REFCOUNT_DEBUG}if FResultValue <> nil then FResultValue.DbgRenameReference(nil, 'DoGetResultValue', @FResultValue, 'DoGetResultValue');{$ENDIF}
2182   FResultValDone := True;
2183   Result := FResultValue;
2184 end;
2185 
2186 procedure TFpPascalExpressionPart.SetParent(AValue: TFpPascalExpressionPartContainer);
2187 begin
2188   if FParent = AValue then Exit;
2189   FParent := AValue;
2190 end;
2191 
2192 procedure TFpPascalExpressionPart.SetStartChar(AValue: PChar);
2193 begin
2194   if FStartChar = AValue then Exit;
2195   FStartChar := AValue;
2196 end;
2197 
TFpPascalExpressionPart.GetTextnull2198 function TFpPascalExpressionPart.GetText(AMaxLen: Integer): String;
2199 var
2200   Len: Integer;
2201 begin
2202   if FEndChar <> nil
2203   then Len := FEndChar - FStartChar + 1
2204   else Len := min(AMaxLen, 10);
2205   if (AMaxLen > 0) and (Len > AMaxLen) then
2206     Len := AMaxLen;
2207   Result := Copy(FStartChar, 1, Len);
2208 end;
2209 
2210 procedure TFpPascalExpressionPart.SetError(AMsg: String);
2211 begin
2212   if AMsg = '' then
2213     AMsg := 'Invalid Expression';
2214   FExpression.SetError(Format('%0:s at %1:d: "%2:s"', [AMsg, FExpression.PosFromPChar(FStartChar), GetText(20)]));
2215 end;
2216 
2217 procedure TFpPascalExpressionPart.SetError(APart: TFpPascalExpressionPart; AMsg: String);
2218 begin
2219   if APart <> nil
2220   then APart.SetError(AMsg)
2221   else Self.SetError(AMsg);
2222 end;
2223 
2224 procedure TFpPascalExpressionPart.SetError(AnErrorCode: TFpErrorCode; AData: array of const);
2225 begin
2226   FExpression.SetError(AnErrorCode, AData);
2227 end;
2228 
2229 procedure TFpPascalExpressionPart.Init;
2230 begin
2231   //
2232 end;
2233 
DoGetIsTypeCastnull2234 function TFpPascalExpressionPart.DoGetIsTypeCast: Boolean;
2235 begin
2236   Result := False;
2237 end;
2238 
TFpPascalExpressionPart.DoGetResultValuenull2239 function TFpPascalExpressionPart.DoGetResultValue: TFpValue;
2240 begin
2241   Result := nil;
2242   SetError('Can not evaluate: "'+GetText+'"');
2243 end;
2244 
2245 procedure TFpPascalExpressionPart.ResetEvaluation;
2246 begin
2247   FResultValue.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FResultValue, 'DoGetResultValue'){$ENDIF};
2248   FResultValue := nil;
2249   FResultValDone := False;
2250 end;
2251 
2252 procedure TFpPascalExpressionPart.ReplaceInParent(AReplacement: TFpPascalExpressionPart);
2253 var
2254   i: Integer;
2255 begin
2256   if Parent = nil then exit;
2257   i := Parent.IndexOf(Self);
2258   Assert(i >= 0);
2259   Parent.Items[i] := AReplacement;
2260   Parent := nil;
2261 end;
2262 
2263 procedure TFpPascalExpressionPart.DoHandleEndOfExpression;
2264 begin
2265   //
2266 end;
2267 
IsValidNextPartnull2268 function TFpPascalExpressionPart.IsValidNextPart(APart: TFpPascalExpressionPart): Boolean;
2269 begin
2270   Result := APart.IsValidAfterPart(Self);
2271 end;
2272 
TFpPascalExpressionPart.IsValidAfterPartnull2273 function TFpPascalExpressionPart.IsValidAfterPart(APrevPart: TFpPascalExpressionPart): Boolean;
2274 begin
2275   Result := True;
2276 end;
2277 
MaybeHandlePrevPartnull2278 function TFpPascalExpressionPart.MaybeHandlePrevPart(APrevPart: TFpPascalExpressionPart;
2279   var AResult: TFpPascalExpressionPart): Boolean;
2280 begin
2281   Result := False;
2282 end;
2283 
TFpPascalExpressionPart.HasPrecedencenull2284 function TFpPascalExpressionPart.HasPrecedence: Boolean;
2285 begin
2286   Result := False;
2287 end;
2288 
TFpPascalExpressionPart.FindLeftSideOperandByPrecedencenull2289 function TFpPascalExpressionPart.FindLeftSideOperandByPrecedence(AnOperator: TFpPascalExpressionPartWithPrecedence): TFpPascalExpressionPart;
2290 begin
2291   Result := Self;
2292 end;
2293 
TFpPascalExpressionPart.CanHaveOperatorAsNextnull2294 function TFpPascalExpressionPart.CanHaveOperatorAsNext: Boolean;
2295 begin
2296   Result := True;
2297 end;
2298 
HandleSeparatornull2299 function TFpPascalExpressionPart.HandleSeparator(ASeparatorType: TSeparatorType): Boolean;
2300 begin
2301   Result := (Parent <> nil) and Parent.HandleSeparator(ASeparatorType);
2302 end;
2303 
DebugTextnull2304 function TFpPascalExpressionPart.DebugText(AIndent: String; AWithResults: Boolean): String;
2305 begin
2306   Result := Format('%s%s at %d: "%s"',
2307                    [AIndent, ClassName, FExpression.PosFromPChar(FStartChar), GetText])
2308                    + LineEnding;
2309 end;
2310 
TFpPascalExpressionPart.DebugDumpnull2311 function TFpPascalExpressionPart.DebugDump(AIndent: String; AWithResults: Boolean): String;
2312 begin
2313   Result := DebugText(AIndent, AWithResults);
2314   if AWithResults and (FResultValue <> nil) then
2315     if (FResultValue is TFpPasParserValue) then
2316       Result := Result + TFpPasParserValue(FResultValue).DebugText(AIndent+'    //  ')
2317     else
2318       Result := Result + AIndent+'    //  FResultValue = ' + DbgSName(FResultValue) + LineEnding;
2319 end;
2320 
2321 constructor TFpPascalExpressionPart.Create(AExpression: TFpPascalExpression; AStartChar: PChar;
2322   AnEndChar: PChar);
2323 begin
2324   FExpression := AExpression;
2325   FStartChar := AStartChar;
2326   FEndChar := AnEndChar;
2327   //FResultTypeFlag := rtUnknown;
2328   FResultValDone := False;
2329   Init;
2330 end;
2331 
2332 destructor TFpPascalExpressionPart.Destroy;
2333 begin
2334   inherited Destroy;
2335   //FResultType.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(nil, 'DoGetResultType'){$ENDIF};
2336   FResultValue.ReleaseReference{$IFDEF WITH_REFCOUNT_DEBUG}(@FResultValue, 'DoGetResultValue'){$ENDIF};
2337 end;
2338 
HandleNextPartnull2339 function TFpPascalExpressionPart.HandleNextPart(APart: TFpPascalExpressionPart): TFpPascalExpressionPart;
2340 begin
2341   Result := APart;
2342   if APart.MaybeHandlePrevPart(Self, Result) then
2343     exit;
2344 
2345   if Parent <> nil then begin
2346     Result := Parent.HandleNextPart(APart);
2347     exit;
2348   end;
2349 
2350   SetError(APart, 'Unexpected ');
2351   APart.Free;
2352   Result := Self;
2353 end;
2354 
2355 procedure TFpPascalExpressionPart.HandleEndOfExpression;
2356 begin
2357   DoHandleEndOfExpression;
2358   if Parent <> nil then
2359     Parent.HandleEndOfExpression;
2360 end;
2361 
2362 { TFpPascalExpressionPartContainer }
2363 
TFpPascalExpressionPartContainer.GetItemsnull2364 function TFpPascalExpressionPartContainer.GetItems(AIndex: Integer): TFpPascalExpressionPart;
2365 begin
2366   Result := TFpPascalExpressionPart(FList[AIndex]);
2367 end;
2368 
TFpPascalExpressionPartContainer.GetLastItemnull2369 function TFpPascalExpressionPartContainer.GetLastItem: TFpPascalExpressionPart;
2370 begin
2371   if Count > 0 then
2372     Result := Items[Count - 1]
2373   else
2374     Result := nil;
2375 end;
2376 
2377 procedure TFpPascalExpressionPartContainer.SetItems(AIndex: Integer;
2378   AValue: TFpPascalExpressionPart);
2379 begin
2380   AValue.Parent := Self;
2381   FList[AIndex] := AValue;
2382 end;
2383 
2384 procedure TFpPascalExpressionPartContainer.SetLastItem(AValue: TFpPascalExpressionPart);
2385 begin
2386   assert(Count >0);
2387   Items[Count-1] := AValue;
2388 end;
2389 
2390 procedure TFpPascalExpressionPartContainer.Init;
2391 begin
2392   FList := TList.Create;
2393   inherited Init;
2394 end;
2395 
TFpPascalExpressionPartContainer.DebugDumpnull2396 function TFpPascalExpressionPartContainer.DebugDump(AIndent: String;
2397   AWithResults: Boolean): String;
2398 var
2399   i: Integer;
2400 begin
2401   Result := inherited DebugDump(AIndent, AWithResults);
2402   for i := 0 to Count - 1 do
2403     Result := Result + Items[i].DebugDump(AIndent+'  ', AWithResults);
2404 end;
2405 
TFpPascalExpressionPartContainer.GetCountnull2406 function TFpPascalExpressionPartContainer.GetCount: Integer;
2407 begin
2408   Result := FList.Count;
2409 end;
2410 
2411 destructor TFpPascalExpressionPartContainer.Destroy;
2412 begin
2413   Clear;
2414   FreeAndNil(FList);
2415   inherited Destroy;
2416 end;
2417 
Addnull2418 function TFpPascalExpressionPartContainer.Add(APart: TFpPascalExpressionPart): Integer;
2419 begin
2420   APart.Parent := Self;
2421   Result := FList.Add(APart);
2422 end;
2423 
TFpPascalExpressionPartContainer.IndexOfnull2424 function TFpPascalExpressionPartContainer.IndexOf(APart: TFpPascalExpressionPart): Integer;
2425 begin
2426   Result := Count - 1;
2427   while (Result >= 0) and (Items[Result] <> APart) do
2428     dec(Result);
2429 end;
2430 
2431 procedure TFpPascalExpressionPartContainer.Clear;
2432 begin
2433   while Count > 0 do begin
2434     Items[0].Free;
2435     FList.Delete(0);
2436   end;
2437 end;
2438 
2439 { TFpPascalExpressionPartBracket }
2440 
TFpPascalExpressionPartBracket.GetAfterCommanull2441 function TFpPascalExpressionPartBracket.GetAfterComma: Boolean;
2442 begin
2443   Result := (FAfterComma = Count);
2444 end;
2445 
2446 procedure TFpPascalExpressionPartBracket.Init;
2447 begin
2448   inherited Init;
2449   FIsClosed := False;
2450   FIsClosing := False;
2451   FAfterComma := -1;
2452 end;
2453 
TFpPascalExpressionPartBracket.HasPrecedencenull2454 function TFpPascalExpressionPartBracket.HasPrecedence: Boolean;
2455 begin
2456   Result := False;
2457 end;
2458 
2459 procedure TFpPascalExpressionPartBracket.DoHandleEndOfExpression;
2460 begin
2461   if not IsClosed then begin
2462     SetError('Bracket not closed');
2463     exit;
2464   end;
2465   inherited DoHandleEndOfExpression;
2466 end;
2467 
CanHaveOperatorAsNextnull2468 function TFpPascalExpressionPartBracket.CanHaveOperatorAsNext: Boolean;
2469 begin
2470   Result := IsClosed;
2471 end;
2472 
HandleNextPartInBracketnull2473 function TFpPascalExpressionPartBracket.HandleNextPartInBracket(APart: TFpPascalExpressionPart): TFpPascalExpressionPart;
2474 begin
2475   Result := Self;
2476   APart.Free;
2477   SetError('Error in ()');
2478 end;
2479 
2480 procedure TFpPascalExpressionPartBracket.SetAfterCommaFlag;
2481 begin
2482   FAfterComma := Count;
2483 end;
2484 
2485 procedure TFpPascalExpressionPartBracket.CloseBracket;
2486 begin
2487   if AfterComma then begin
2488     SetError(fpErrPasParserMissingExprAfterComma, [GetText]);
2489     exit;
2490   end;
2491   FIsClosing := True;
2492   if LastItem <> nil then
2493     LastItem.HandleEndOfExpression;
2494   FIsClosing := False;
2495   FIsClosed := True;
2496 end;
2497 
HandleNextPartnull2498 function TFpPascalExpressionPartBracket.HandleNextPart(APart: TFpPascalExpressionPart): TFpPascalExpressionPart;
2499 begin
2500   if IsClosed then begin
2501     Result := inherited HandleNextPart(APart);
2502     exit;
2503   end;
2504 
2505   if not IsValidNextPart(APart) then begin
2506     SetError(APart, 'Invalid operand in () '+GetText+': ');
2507     Result := self;
2508     APart.Free;
2509     exit;
2510   end;
2511 
2512   Result := HandleNextPartInBracket(APart);
2513 end;
2514 
2515 procedure TFpPascalExpressionPartBracket.HandleEndOfExpression;
2516 begin
2517   if not FIsClosing then
2518     inherited HandleEndOfExpression;
2519 end;
2520 
2521 { TFpPascalExpressionPartOperator }
2522 
TFpPascalExpressionPartOperator.DebugTextnull2523 function TFpPascalExpressionPartOperator.DebugText(AIndent: String;
2524   AWithResults: Boolean): String;
2525 begin
2526   Result := inherited DebugText(AIndent, AWithResults);
2527   while Result[Length(Result)] in [#10, #13] do SetLength(Result, Length(Result)-1);
2528   Result := Result + ' Precedence:' + dbgs(FPrecedence) +
2529     LineEnding;
2530 end;
2531 
TFpPascalExpressionPartOperator.CanHaveOperatorAsNextnull2532 function TFpPascalExpressionPartOperator.CanHaveOperatorAsNext: Boolean;
2533 begin
2534   Result := HasAllOperands and LastItem.CanHaveOperatorAsNext;
2535 end;
2536 
TFpPascalExpressionPartOperator.FindLeftSideOperandByPrecedencenull2537 function TFpPascalExpressionPartOperator.FindLeftSideOperandByPrecedence(AnOperator: TFpPascalExpressionPartWithPrecedence): TFpPascalExpressionPart;
2538 begin
2539   Result := Self;
2540 
2541   if (not HasAllOperands) or (LastItem = nil) then begin
2542     Result := nil;
2543     exit
2544   end;
2545 
2546   // precedence: 1 = highest
2547   if Precedence > AnOperator.Precedence then
2548     Result := LastItem.FindLeftSideOperandByPrecedence(AnOperator);
2549 end;
2550 
TFpPascalExpressionPartOperator.MaybeAddLeftOperandnull2551 function TFpPascalExpressionPartOperator.MaybeAddLeftOperand(APrevPart: TFpPascalExpressionPart;
2552   var AResult: TFpPascalExpressionPart): Boolean;
2553 var
2554   ALeftSide: TFpPascalExpressionPart;
2555 begin
2556   Result := APrevPart.IsValidNextPart(Self);
2557   if not Result then
2558     exit;
2559 
2560   AResult := Self;
2561   if (Count > 0) or // Previous already set
2562      (not APrevPart.CanHaveOperatorAsNext) // can not have 2 operators follow each other
2563   then begin
2564     SetError(APrevPart, 'Can not apply operator '+GetText+': ');
2565     APrevPart.Free;
2566     exit;
2567   end;
2568 
2569   ALeftSide := APrevPart.FindLeftSideOperandByPrecedence(Self);
2570   if ALeftSide = nil then begin
2571     SetError(Self, 'Internal parser error for operator '+GetText+': ');
2572     APrevPart.Free;
2573     exit;
2574   end;
2575 
2576   ALeftSide.ReplaceInParent(Self);
2577   Add(ALeftSide);
2578 end;
2579 
2580 procedure TFpPascalExpressionPartOperator.DoHandleEndOfExpression;
2581 begin
2582   if not HasAllOperands then
2583     SetError(Self, 'Not enough operands')
2584   else
2585     inherited DoHandleEndOfExpression;
2586 end;
2587 
TFpPascalExpressionPartOperator.HandleSeparatornull2588 function TFpPascalExpressionPartOperator.HandleSeparator(ASeparatorType: TSeparatorType): Boolean;
2589 begin
2590   Result := HasAllOperands and (inherited HandleSeparator(ASeparatorType));
2591 end;
2592 
TFpPascalExpressionPartOperator.HandleNextPartnull2593 function TFpPascalExpressionPartOperator.HandleNextPart(APart: TFpPascalExpressionPart): TFpPascalExpressionPart;
2594 begin
2595   Result := Self;
2596   if HasAllOperands then begin
2597     Result := inherited HandleNextPart(APart);
2598     exit;
2599   end;
2600   if not IsValidNextPart(APart) then begin
2601     SetError(APart, 'Not possible after Operator '+GetText+': ');
2602     APart.Free;
2603     exit;
2604   end;
2605 
2606   Add(APart);
2607   Result := APart;
2608 end;
2609 
2610 { TFpPascalExpressionPartUnaryOperator }
2611 
HasAllOperandsnull2612 function TFpPascalExpressionPartUnaryOperator.HasAllOperands: Boolean;
2613 begin
2614   Result := Count = 1;
2615 end;
2616 
2617 { TFpPascalExpressionPartBinaryOperator }
2618 
HasAllOperandsnull2619 function TFpPascalExpressionPartBinaryOperator.HasAllOperands: Boolean;
2620 begin
2621   Result := Count = 2;
2622 end;
2623 
TFpPascalExpressionPartBinaryOperator.IsValidAfterPartnull2624 function TFpPascalExpressionPartBinaryOperator.IsValidAfterPart(APrevPart: TFpPascalExpressionPart): Boolean;
2625 begin
2626   Result := inherited IsValidAfterPart(APrevPart);
2627   if not Result then
2628     exit;
2629 
2630   Result := APrevPart.CanHaveOperatorAsNext;
2631 
2632   // BinaryOperator...
2633   //   foo
2634   //   Identifier
2635   // "Identifier" can hane a binary-op next. But it must be applied to the parent.
2636   // So it is not valid here.
2637   // If new operator has a higher precedence, it go down to the child again and replace it
2638   if (APrevPart.Parent <> nil) and (APrevPart.Parent.HasPrecedence) then
2639     Result := False;
2640 end;
2641 
MaybeHandlePrevPartnull2642 function TFpPascalExpressionPartBinaryOperator.MaybeHandlePrevPart(APrevPart: TFpPascalExpressionPart;
2643   var AResult: TFpPascalExpressionPart): Boolean;
2644 begin
2645   Result := MaybeAddLeftOperand(APrevPart, AResult);
2646 end;
2647 
2648 { TFpPascalExpressionPartOperatorAddressOf }
2649 
2650 procedure TFpPascalExpressionPartOperatorAddressOf.Init;
2651 begin
2652   FPrecedence := PRECEDENCE_ADRESS_OF;
2653   inherited Init;
2654 end;
2655 
TFpPascalExpressionPartOperatorAddressOf.DoGetResultValuenull2656 function TFpPascalExpressionPartOperatorAddressOf.DoGetResultValue: TFpValue;
2657 var
2658   tmp: TFpValue;
2659 begin
2660   Result := nil;
2661   if Count <> 1 then exit;
2662 
2663   tmp := Items[0].ResultValue;
2664   if (tmp = nil) or not IsTargetAddr(tmp.Address) then
2665     exit;
2666 
2667   Result := TFpPasParserValueAddressOf.Create(tmp, Expression.Context.LocationContext);
2668   {$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue');{$ENDIF}
2669 end;
2670 
2671 { TFpPascalExpressionPartOperatorMakeRef }
2672 
2673 procedure TFpPascalExpressionPartOperatorMakeRef.Init;
2674 begin
2675   FPrecedence := PRECEDENCE_MAKE_REF;
2676   inherited Init;
2677 end;
2678 
IsValidNextPartnull2679 function TFpPascalExpressionPartOperatorMakeRef.IsValidNextPart(APart: TFpPascalExpressionPart): Boolean;
2680 begin
2681   if HasAllOperands then
2682     Result := (inherited IsValidNextPart(APart))
2683   else
2684     Result := (inherited IsValidNextPart(APart)) and
2685               ( (APart is TFpPascalExpressionPartIdentifier) or
2686                 (APart is TFpPascalExpressionPartOperatorMakeRef)
2687               );
2688 end;
2689 
TFpPascalExpressionPartOperatorMakeRef.DoGetResultValuenull2690 function TFpPascalExpressionPartOperatorMakeRef.DoGetResultValue: TFpValue;
2691 var
2692   tmp: TFpValue;
2693 begin
2694   Result := nil;
2695   if Count <> 1 then exit;
2696 
2697   tmp := Items[0].ResultValue;
2698   if tmp = nil then
2699     exit;
2700   if tmp is TFpPasParserValueMakeReftype then begin
2701     TFpPasParserValueMakeReftype(tmp).IncRefLevel;
2702     Result := tmp;
2703     Result.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(nil, 'DoGetResultValue'){$ENDIF};
2704     exit;
2705   end;
2706 
2707   if (tmp.DbgSymbol = nil) or (tmp.DbgSymbol.SymbolType <> stType) then
2708     exit;
2709 
2710   Result := TFpPasParserValueMakeReftype.Create(tmp.DbgSymbol, Expression.Context.LocationContext);
2711   {$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue'){$ENDIF};
2712 end;
2713 
DoGetIsTypeCastnull2714 function TFpPascalExpressionPartOperatorMakeRef.DoGetIsTypeCast: Boolean;
2715 begin
2716   Result := True;
2717 end;
2718 
2719 { TFpPascalExpressionPartOperatorDeRef }
2720 
2721 procedure TFpPascalExpressionPartOperatorDeRef.Init;
2722 begin
2723   FPrecedence := PRECEDENCE_DEREF;
2724   inherited Init;
2725 end;
2726 
TFpPascalExpressionPartOperatorDeRef.DoGetResultValuenull2727 function TFpPascalExpressionPartOperatorDeRef.DoGetResultValue: TFpValue;
2728 var
2729   tmp: TFpValue;
2730 begin
2731   Result := nil;
2732   if Count <> 1 then exit;
2733 
2734   tmp := Items[0].ResultValue;
2735   if tmp = nil then
2736     exit;
2737 
2738   if tmp is TFpPasParserValueAddressOf then begin // TODO: remove IF, handled in GetMember
2739     Result := TFpPasParserValueAddressOf(tmp).PointedToValue;
2740     Result.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(nil, 'DoGetResultValue'){$ENDIF};
2741   end
2742   else
2743   if tmp.Kind = skPointer then begin
2744     if (svfDataAddress in tmp.FieldFlags) and (IsReadableLoc(tmp.DataAddress)) and // TODO, what if Not readable addr
2745        (tmp.TypeInfo <> nil) //and (tmp.TypeInfo.TypeInfo <> nil)
2746     then begin
2747       Result := tmp.Member[0];
2748       if Result <> nil then
2749         {$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue'){$ENDIF};
2750 
2751     end;
2752   end
2753   //if tmp.Kind = skArray then // dynarray
2754   else
2755   begin
2756     Result := nil;
2757     SetError(fpErrCannotDereferenceType, [GetText]);
2758   end;
2759 end;
2760 
MaybeHandlePrevPartnull2761 function TFpPascalExpressionPartOperatorDeRef.MaybeHandlePrevPart(APrevPart: TFpPascalExpressionPart;
2762   var AResult: TFpPascalExpressionPart): Boolean;
2763 begin
2764   Result := MaybeAddLeftOperand(APrevPart, AResult);
2765 end;
2766 
TFpPascalExpressionPartOperatorDeRef.FindLeftSideOperandByPrecedencenull2767 function TFpPascalExpressionPartOperatorDeRef.FindLeftSideOperandByPrecedence(AnOperator: TFpPascalExpressionPartWithPrecedence): TFpPascalExpressionPart;
2768 begin
2769   Result := Self;
2770 end;
2771 
TFpPascalExpressionPartOperatorDeRef.IsValidAfterPartnull2772 function TFpPascalExpressionPartOperatorDeRef.IsValidAfterPart(APrevPart: TFpPascalExpressionPart): Boolean;
2773 begin
2774   Result := inherited IsValidAfterPart(APrevPart);
2775   if not Result then
2776     exit;
2777 
2778   Result := APrevPart.CanHaveOperatorAsNext;
2779 
2780   // BinaryOperator...
2781   //   foo
2782   //   Identifier
2783   // "Identifier" can hane a binary-op next. But it must be applied to the parent.
2784   // So it is not valid here.
2785   // If new operator has a higher precedence, it go down to the child again and replace it
2786   if (APrevPart.Parent <> nil) and (APrevPart.Parent is TFpPascalExpressionPartOperator) then
2787     Result := False;
2788 end;
2789 
2790 { TFpPascalExpressionPartOperatorUnaryPlusMinus }
2791 
2792 procedure TFpPascalExpressionPartOperatorUnaryPlusMinus.Init;
2793 begin
2794   FPrecedence := PRECEDENCE_UNARY_SIGN;
2795   inherited Init;
2796 end;
2797 
TFpPascalExpressionPartOperatorUnaryPlusMinus.DoGetResultValuenull2798 function TFpPascalExpressionPartOperatorUnaryPlusMinus.DoGetResultValue: TFpValue;
2799 var
2800   tmp1: TFpValue;
2801   IsAdd: Boolean;
2802 begin
2803   Result := nil;
2804   if Count <> 1 then exit;
2805   assert((GetText = '+') or (GetText = '-'), 'TFpPascalExpressionPartOperatorUnaryPlusMinus.DoGetResultValue: (GetText = +) or (GetText = -)');
2806 
2807   tmp1 := Items[0].ResultValue;
2808   IsAdd := GetText = '+';
2809   if (tmp1 = nil) then exit;
2810 
2811   {$PUSH}{$R-}{$Q-}
2812   if IsAdd then begin
2813     case tmp1.Kind of
2814       skPointer: ;
2815       skInteger:  Result := tmp1;
2816       skCardinal: Result := tmp1;
2817       skFloat:    Result := tmp1;
2818     end;
2819     Result.AddReference{$IFDEF WITH_REFCOUNT_DEBUG}(nil, 'DoGetResultValue'){$ENDIF};
2820   end
2821   else begin
2822     case tmp1.Kind of
2823       skPointer: ;
2824       skInteger:  Result := TFpValueConstNumber.Create(-tmp1.AsInteger, True);
2825       skCardinal: Result := TFpValueConstNumber.Create(-tmp1.AsCardinal, True);
2826       skFloat:    Result := TFpValueConstFloat.Create(-tmp1.AsFloat);
2827     end;
2828     {$IFDEF WITH_REFCOUNT_DEBUG}if Result <> nil then Result.DbgRenameReference(nil, 'DoGetResultValue');{$ENDIF}
2829   end;
2830   {$POP}
2831 
2832 end;
2833 
2834 { TFpPascalExpressionPartOperatorPlusMinus }
2835 
2836 procedure TFpPascalExpressionPartOperatorPlusMinus.Init;
2837 begin
2838   FPrecedence := PRECEDENCE_PLUS_MINUS;
2839   inherited Init;
2840 end;
2841 
TFpPascalExpressionPartOperatorPlusMinus.DoGetResultValuenull2842 function TFpPascalExpressionPartOperatorPlusMinus.DoGetResultValue: TFpValue;
2843 {$PUSH}{$R-}{$Q-}
AddSubValueToPointernull2844   function AddSubValueToPointer(APointerVal, AOtherVal: TFpValue; ADoSubtract: Boolean = False): TFpValue;
2845   var
2846     Idx, m: Int64;
2847     TmpVal: TFpValue;
2848     s1, s2: TFpDbgValueSize;
2849   begin
2850     Result := nil;
2851     case AOtherVal.Kind of
2852       skPointer: if ADoSubtract then begin
2853           if ( (APointerVal.TypeInfo = nil) or (APointerVal.TypeInfo.TypeInfo = nil) ) and
2854              ( (AOtherVal.TypeInfo = nil)   or (AOtherVal.TypeInfo.TypeInfo = nil) )
2855           then begin
2856             Idx := APointerVal.AsCardinal - AOtherVal.AsCardinal;
2857             Result := TFpValueConstNumber.Create(Idx, True);
2858             exit;
2859           end
2860           else
2861           if (APointerVal.TypeInfo <> nil) and (APointerVal.TypeInfo.TypeInfo <> nil) and
2862              (AOtherVal.TypeInfo <> nil)   and (AOtherVal.TypeInfo.TypeInfo <> nil) and
2863              (APointerVal.TypeInfo.TypeInfo.Kind = AOtherVal.TypeInfo.TypeInfo.Kind) and
2864              (APointerVal.TypeInfo.TypeInfo.ReadSize(nil, s1)) and
2865              (AOtherVal.TypeInfo.TypeInfo.ReadSize(nil, s2)) and
2866              (s1 = s2)
2867           then begin
2868             TmpVal := APointerVal.Member[1];
2869             if s1 <> (TmpVal.DataAddress.Address - APointerVal.DataAddress.Address) then begin
2870               TmpVal.ReleaseReference;
2871               debugln('Size mismatch for pointer math');
2872               exit;
2873             end;
2874             TmpVal.ReleaseReference;
2875             Idx := APointerVal.AsCardinal - AOtherVal.AsCardinal;
2876             if SizeToFullBytes(s1) > 0 then begin
2877               m := Idx mod SizeToFullBytes(s1);
2878               Idx := Idx div SizeToFullBytes(s1);
2879               if m <> 0 then begin
2880                 debugln('Size mismatch for pointer math');
2881                 exit;
2882               end;
2883             end;
2884 
2885             Result := TFpValueConstNumber.Create(Idx, True);
2886             exit;
2887           end
2888           else
2889             exit;
2890         end
2891         else
2892           exit;
2893       skInteger:  Idx := AOtherVal.AsInteger;
2894       skCardinal: begin
2895           Idx := AOtherVal.AsInteger;
2896           if Idx > High(Int64) then
2897             exit; // TODO: error
2898         end;
2899       else
2900         exit; // TODO: error
2901     end;
2902     if ADoSubtract then begin
2903       if Idx < -(High(Int64)) then
2904         exit; // TODO: error
2905       Idx := -Idx;
2906     end;
2907     TmpVal := APointerVal.Member[Idx];
2908     if IsError(APointerVal.LastError) or (TmpVal = nil) then begin
2909       SetError('Error dereferencing'); // TODO: set correct error
2910       exit;
2911     end;
2912     Result := TFpPasParserValueAddressOf.Create(TmpVal, Expression.Context.LocationContext);
2913     TmpVal.ReleaseReference;
2914   end;
AddValueToIntnull2915   function AddValueToInt(AIntVal, AOtherVal: TFpValue): TFpValue;
2916   begin
2917     Result := nil;
2918     case AOtherVal.Kind of
2919       skPointer:  Result := AddSubValueToPointer(AOtherVal, AIntVal);
2920       skInteger:  Result := TFpValueConstNumber.Create(AIntVal.AsInteger + AOtherVal.AsInteger, True);
2921       skCardinal: Result := TFpValueConstNumber.Create(AIntVal.AsInteger + AOtherVal.AsCardinal, True);
2922       skFloat:    Result := TFpValueConstFloat.Create(AIntVal.AsInteger + AOtherVal.AsFloat);
2923       else SetError('Addition not supported');
2924     end;
2925   end;
AddValueToCardinalnull2926   function AddValueToCardinal(ACardinalVal, AOtherVal: TFpValue): TFpValue;
2927   begin
2928     Result := nil;
2929     case AOtherVal.Kind of
2930       skPointer:  Result := AddSubValueToPointer(AOtherVal, ACardinalVal);
2931       skInteger:  Result := TFpValueConstNumber.Create(ACardinalVal.AsCardinal + AOtherVal.AsInteger, True);
2932       skCardinal: Result := TFpValueConstNumber.Create(ACardinalVal.AsCardinal + AOtherVal.AsCardinal, False);
2933       skFloat:    Result := TFpValueConstFloat.Create(ACardinalVal.AsCardinal + AOtherVal.AsFloat);
2934       else SetError('Addition not supported');
2935     end;
2936   end;
AddValueToFloatnull2937   function AddValueToFloat(AFloatVal, AOtherVal: TFpValue): TFpValue;
2938   begin
2939     Result := nil;
2940     case AOtherVal.Kind of
2941       skInteger:  Result := TFpValueConstFloat.Create(AFloatVal.AsFloat + AOtherVal.AsInteger);
2942       skCardinal: Result := TFpValueConstFloat.Create(AFloatVal.AsFloat + AOtherVal.AsCardinal);
2943       skFloat:    Result := TFpValueConstFloat.Create(AFloatVal.AsFloat + AOtherVal.AsFloat);
2944       else SetError('Addition not supported');
2945     end;
2946   end;
ConcateCharDatanull2947   function ConcateCharData(ACharVal, AOtherVal: TFpValue): TFpValue;
2948   begin
2949     Result := nil;
2950     if AOtherVal.FieldFlags * [svfString, svfWideString] <> [] then
2951       Result := TFpValueConstString.Create(ACharVal.AsString + AOtherVal.AsString)
2952     else
2953       SetError('Operation + not supported');
2954   end;
2955 
SubPointerFromValuenull2956   function SubPointerFromValue(APointerVal, AOtherVal: TFpValue): TFpValue;
2957   begin
2958     Result := nil;       // Error
2959   end;
SubValueFromIntnull2960   function SubValueFromInt(AIntVal, AOtherVal: TFpValue): TFpValue;
2961   begin
2962     Result := nil;
2963     case AOtherVal.Kind of
2964       skPointer:  Result := SubPointerFromValue(AOtherVal, AIntVal);
2965       skInteger:  Result := TFpValueConstNumber.Create(AIntVal.AsInteger - AOtherVal.AsInteger, True);
2966       skCardinal: Result := TFpValueConstNumber.Create(AIntVal.AsInteger - AOtherVal.AsCardinal, True);
2967       skFloat:    Result := TFpValueConstFloat.Create(AIntVal.AsInteger - AOtherVal.AsFloat);
2968       else SetError('Subtraction not supported');
2969     end;
2970   end;
SubValueFromCardinalnull2971   function SubValueFromCardinal(ACardinalVal, AOtherVal: TFpValue): TFpValue;
2972   begin
2973     Result := nil;
2974     case AOtherVal.Kind of
2975       skPointer:  Result := SubPointerFromValue(AOtherVal, ACardinalVal);
2976       skInteger:  Result := TFpValueConstNumber.Create(ACardinalVal.AsCardinal - AOtherVal.AsInteger, True);
2977       skCardinal: Result := TFpValueConstNumber.Create(ACardinalVal.AsCardinal - AOtherVal.AsCardinal, False);
2978       skFloat:    Result := TFpValueConstFloat.Create(ACardinalVal.AsCardinal - AOtherVal.AsFloat);
2979       else SetError('Subtraction not supported');
2980     end;
2981   end;
SubValueFromFloatnull2982   function SubValueFromFloat(AFloatVal, AOtherVal: TFpValue): TFpValue;
2983   begin
2984     Result := nil;
2985     case AOtherVal.Kind of
2986       skInteger:  Result := TFpValueConstFloat.Create(AFloatVal.AsFloat - AOtherVal.AsInteger);
2987       skCardinal: Result := TFpValueConstFloat.Create(AFloatVal.AsFloat - AOtherVal.AsCardinal);
2988       skFloat:    Result := TFpValueConstFloat.Create(AFloatVal.AsFloat - AOtherVal.AsFloat);
2989       else SetError('Subtraction not supported');
2990     end;
2991   end;
2992 {$POP}
2993 var
2994   tmp1, tmp2: TFpValue;
2995   IsAdd: Boolean;
2996 begin
2997   Result := nil;
2998   if Count <> 2 then exit;
2999   assert((GetText = '+') or (GetText = '-'), 'TFpPascalExpressionPartOperatorUnaryPlusMinus.DoGetResultValue: (GetText = +) or (GetText = -)');
3000 
3001   tmp1 := Items[0].ResultValue;
3002   tmp2 := Items[1].ResultValue;
3003   IsAdd := GetText = '+';
3004   if (tmp1 = nil) or (tmp2 = nil) then exit;
3005 
3006   if IsAdd then begin
3007     case tmp1.Kind of
3008       skInteger:  Result := AddValueToInt(tmp1, tmp2);
3009       skCardinal: Result := AddValueToCardinal(tmp1, tmp2);
3010       skFloat:    Result := AddValueToFloat(tmp1, tmp2);
3011       skPointer: begin
3012                   // Pchar can concatenate with String. But not with other Pchar
3013                   // Maybe allow optional: This does limit undetected/mis-detected strings
3014                   if (tmp1.FieldFlags * [svfString, svfWideString] <> []) and
3015                      (tmp2.Kind in [skString, skAnsiString, skWideString, skChar{, skWideChar}])
3016                   then
3017                     Result := ConcateCharData(tmp1, tmp2)
3018                   else
3019                     Result := AddSubValueToPointer(tmp1, tmp2);
3020                  end;
3021       skString, skAnsiString, skWideString, skChar{, skWideChar}:
3022                   Result := ConcateCharData(tmp1, tmp2);
3023     end;
3024   end
3025   else begin
3026     case tmp1.Kind of
3027       skPointer:  Result := AddSubValueToPointer(tmp1, tmp2, True);
3028       skInteger:  Result := SubValueFromInt(tmp1, tmp2);
3029       skCardinal: Result := SubValueFromCardinal(tmp1, tmp2);
3030       skFloat:    Result := SubValueFromFloat(tmp1, tmp2);
3031     end;
3032   end;
3033 
3034  {$IFDEF WITH_REFCOUNT_DEBUG}if Result <> nil then
3035    Result.DbgRenameReference(nil, 'DoGetResultValue');{$ENDIF}
3036 end;
3037 
3038 { TFpPascalExpressionPartOperatorMulDiv }
3039 
3040 procedure TFpPascalExpressionPartOperatorMulDiv.Init;
3041 begin
3042   FPrecedence := PRECEDENCE_MUL_DIV;
3043   inherited Init;
3044 end;
3045 
TFpPascalExpressionPartOperatorMulDiv.DoGetResultValuenull3046 function TFpPascalExpressionPartOperatorMulDiv.DoGetResultValue: TFpValue;
3047 {$PUSH}{$R-}{$Q-}
MultiplyIntWithValuenull3048   function MultiplyIntWithValue(AIntVal, AOtherVal: TFpValue): TFpValue;
3049   begin
3050     Result := nil;
3051     case AOtherVal.Kind of
3052       skInteger:  Result := TFpValueConstNumber.Create(AIntVal.AsInteger * AOtherVal.AsInteger, True);
3053       skCardinal: Result := TFpValueConstNumber.Create(AIntVal.AsInteger * AOtherVal.AsCardinal, True);
3054       skFloat:    Result := TFpValueConstFloat.Create(AIntVal.AsInteger * AOtherVal.AsFloat);
3055       else SetError('Multiply not supported');
3056     end;
3057   end;
MultiplyCardinalWithValuenull3058   function MultiplyCardinalWithValue(ACardinalVal, AOtherVal: TFpValue): TFpValue;
3059   begin
3060     Result := nil;
3061     case AOtherVal.Kind of
3062       skInteger:  Result := TFpValueConstNumber.Create(ACardinalVal.AsCardinal * AOtherVal.AsInteger, True);
3063       skCardinal: Result := TFpValueConstNumber.Create(ACardinalVal.AsCardinal * AOtherVal.AsCardinal, False);
3064       skFloat:    Result := TFpValueConstFloat.Create(ACardinalVal.AsCardinal * AOtherVal.AsFloat);
3065       else SetError('Multiply not supported');
3066     end;
3067   end;
MultiplyFloatWithValuenull3068   function MultiplyFloatWithValue(AFloatVal, AOtherVal: TFpValue): TFpValue;
3069   begin
3070     Result := nil;
3071     case AOtherVal.Kind of
3072       skInteger:  Result := TFpValueConstFloat.Create(AFloatVal.AsFloat * AOtherVal.AsInteger);
3073       skCardinal: Result := TFpValueConstFloat.Create(AFloatVal.AsFloat * AOtherVal.AsCardinal);
3074       skFloat:    Result := TFpValueConstFloat.Create(AFloatVal.AsFloat * AOtherVal.AsFloat);
3075       else SetError('Multiply not supported');
3076     end;
3077   end;
3078 
FloatDivIntByValuenull3079   function FloatDivIntByValue(AIntVal, AOtherVal: TFpValue): TFpValue;
3080   begin
3081     Result := nil;
3082     case AOtherVal.Kind of
3083       skInteger:  Result := TFpValueConstFloat.Create(AIntVal.AsInteger / AOtherVal.AsInteger);
3084       skCardinal: Result := TFpValueConstFloat.Create(AIntVal.AsInteger / AOtherVal.AsCardinal);
3085       skFloat:    Result := TFpValueConstFloat.Create(AIntVal.AsInteger / AOtherVal.AsFloat);
3086       else SetError('/ not supported');
3087     end;
3088   end;
FloatDivCardinalByValuenull3089   function FloatDivCardinalByValue(ACardinalVal, AOtherVal: TFpValue): TFpValue;
3090   begin
3091     Result := nil;
3092     case AOtherVal.Kind of
3093       skInteger:  Result := TFpValueConstFloat.Create(ACardinalVal.AsCardinal / AOtherVal.AsInteger);
3094       skCardinal: Result := TFpValueConstFloat.Create(ACardinalVal.AsCardinal / AOtherVal.AsCardinal);
3095       skFloat:    Result := TFpValueConstFloat.Create(ACardinalVal.AsCardinal / AOtherVal.AsFloat);
3096       else SetError('/ not supported');
3097     end;
3098   end;
FloatDivFloatByValuenull3099   function FloatDivFloatByValue(AFloatVal, AOtherVal: TFpValue): TFpValue;
3100   begin
3101     Result := nil;
3102     case AOtherVal.Kind of
3103       skInteger:  Result := TFpValueConstFloat.Create(AFloatVal.AsFloat / AOtherVal.AsInteger);
3104       skCardinal: Result := TFpValueConstFloat.Create(AFloatVal.AsFloat / AOtherVal.AsCardinal);
3105       skFloat:    Result := TFpValueConstFloat.Create(AFloatVal.AsFloat / AOtherVal.AsFloat);
3106       else SetError('/ not supported');
3107     end;
3108   end;
3109 
NumDivIntByValuenull3110   function NumDivIntByValue(AIntVal, AOtherVal: TFpValue): TFpValue;
3111   begin
3112     Result := nil;
3113     case AOtherVal.Kind of
3114       skInteger:  Result := TFpValueConstNumber.Create(AIntVal.AsInteger div AOtherVal.AsInteger, True);
3115       skCardinal: Result := TFpValueConstNumber.Create(AIntVal.AsInteger div AOtherVal.AsCardinal, True);
3116       else SetError('Div not supported');
3117     end;
3118   end;
NumDivCardinalByValuenull3119   function NumDivCardinalByValue(ACardinalVal, AOtherVal: TFpValue): TFpValue;
3120   begin
3121     Result := nil;
3122     case AOtherVal.Kind of
3123       skInteger:  Result := TFpValueConstNumber.Create(ACardinalVal.AsCardinal div AOtherVal.AsInteger, True);
3124       skCardinal: Result := TFpValueConstNumber.Create(ACardinalVal.AsCardinal div AOtherVal.AsCardinal, False);
3125       else SetError('Div not supported');
3126     end;
3127   end;
3128 
NumModIntByValuenull3129   function NumModIntByValue(AIntVal, AOtherVal: TFpValue): TFpValue;
3130   begin
3131     Result := nil;
3132     case AOtherVal.Kind of
3133       skInteger:  Result := TFpValueConstNumber.Create(AIntVal.AsInteger mod AOtherVal.AsInteger, True);
3134       skCardinal: Result := TFpValueConstNumber.Create(AIntVal.AsInteger mod AOtherVal.AsCardinal, True);
3135       else SetError('Div not supported');
3136     end;
3137   end;
NumModCardinalByValuenull3138   function NumModCardinalByValue(ACardinalVal, AOtherVal: TFpValue): TFpValue;
3139   begin
3140     Result := nil;
3141     case AOtherVal.Kind of
3142       skInteger:  Result := TFpValueConstNumber.Create(ACardinalVal.AsCardinal mod AOtherVal.AsInteger, True);
3143       skCardinal: Result := TFpValueConstNumber.Create(ACardinalVal.AsCardinal mod AOtherVal.AsCardinal, False);
3144       else SetError('Mod not supported');
3145     end;
3146   end;
3147 {$POP}
3148 var
3149   tmp1, tmp2: TFpValue;
3150 begin
3151   Result := nil;
3152   if Count <> 2 then exit;
3153 
3154   tmp1 := Items[0].ResultValue;
3155   tmp2 := Items[1].ResultValue;
3156   if (tmp1 = nil) or (tmp2 = nil) then exit;
3157 
3158   if GetText = '*' then begin
3159     case tmp1.Kind of
3160       skInteger:  Result := MultiplyIntWithValue(tmp1, tmp2);
3161       skCardinal: Result := MultiplyCardinalWithValue(tmp1, tmp2);
3162       skFloat:    Result := MultiplyFloatWithValue(tmp1, tmp2);
3163     end;
3164   end
3165   else
3166   if GetText = '/' then begin
3167     case tmp1.Kind of
3168       skInteger:  Result := FloatDivIntByValue(tmp1, tmp2);
3169       skCardinal: Result := FloatDivCardinalByValue(tmp1, tmp2);
3170       skFloat:    Result := FloatDivFloatByValue(tmp1, tmp2);
3171     end;
3172   end
3173   else
3174   if CompareText(GetText, 'div') = 0 then begin
3175     case tmp1.Kind of
3176       skInteger:  Result := NumDivIntByValue(tmp1, tmp2);
3177       skCardinal: Result := NumDivCardinalByValue(tmp1, tmp2);
3178     end;
3179   end
3180   else
3181   if CompareText(GetText, 'mod') = 0 then begin
3182     case tmp1.Kind of
3183       skInteger:  Result := NumModIntByValue(tmp1, tmp2);
3184       skCardinal: Result := NumModCardinalByValue(tmp1, tmp2);
3185     end;
3186   end;
3187 
3188  {$IFDEF WITH_REFCOUNT_DEBUG}if Result <> nil then
3189    Result.DbgRenameReference(nil, 'DoGetResultValue');{$ENDIF}
3190 end;
3191 
3192 { TFpPascalExpressionPartOperatorUnaryNot }
3193 
3194 procedure TFpPascalExpressionPartOperatorUnaryNot.Init;
3195 begin
3196   FPrecedence := PRECEDENCE_UNARY_NOT;
3197   inherited Init;
3198 end;
3199 
TFpPascalExpressionPartOperatorUnaryNot.DoGetResultValuenull3200 function TFpPascalExpressionPartOperatorUnaryNot.DoGetResultValue: TFpValue;
3201 var
3202   tmp1: TFpValue;
3203 begin
3204   Result := nil;
3205   if Count <> 1 then exit;
3206 
3207   tmp1 := Items[0].ResultValue;
3208   if (tmp1 = nil) then exit;
3209 
3210   {$PUSH}{$R-}{$Q-}
3211   case tmp1.Kind of
3212     skInteger: Result := TFpValueConstNumber.Create(not tmp1.AsInteger, True);
3213     skCardinal: Result := TFpValueConstNumber.Create(not tmp1.AsCardinal, False);
3214     skBoolean: Result := TFpValueConstBool.Create(not tmp1.AsBool);
3215   end;
3216   {$POP}
3217 
3218  {$IFDEF WITH_REFCOUNT_DEBUG}if Result <> nil then Result.DbgRenameReference(nil, 'DoGetResultValue');{$ENDIF}
3219 end;
3220 
3221 { TFpPascalExpressionPartOperatorAnd }
3222 
3223 procedure TFpPascalExpressionPartOperatorAnd.Init;
3224 begin
3225   FPrecedence := PRECEDENCE_AND;
3226   inherited Init;
3227 end;
3228 
TFpPascalExpressionPartOperatorAnd.DoGetResultValuenull3229 function TFpPascalExpressionPartOperatorAnd.DoGetResultValue: TFpValue;
3230 var
3231   tmp1, tmp2: TFpValue;
3232 begin
3233   Result := nil;
3234   if Count <> 2 then exit;
3235 
3236   tmp1 := Items[0].ResultValue;
3237   tmp2 := Items[1].ResultValue;
3238   if (tmp1 = nil) or (tmp2 = nil) then exit;
3239 
3240   {$PUSH}{$R-}{$Q-}
3241   case tmp1.Kind of
3242     skInteger: if tmp2.Kind = skInteger then
3243                  Result := TFpValueConstNumber.Create(tmp1.AsInteger AND tmp2.AsInteger, True)
3244                else
3245                   Result := TFpValueConstNumber.Create(tmp1.AsCardinal AND tmp2.AsCardinal, False);
3246     skCardinal: if tmp2.Kind in [skInteger, skCardinal] then
3247                   Result := TFpValueConstNumber.Create(tmp1.AsCardinal AND tmp2.AsCardinal, False);
3248     skBoolean: if tmp2.Kind = skBoolean then
3249                  Result := TFpValueConstBool.Create(tmp1.AsBool AND tmp2.AsBool);
3250   end;
3251   {$POP}
3252 
3253  {$IFDEF WITH_REFCOUNT_DEBUG}if Result <> nil then Result.DbgRenameReference(nil, 'DoGetResultValue');{$ENDIF}
3254 end;
3255 
3256 { TFpPascalExpressionPartOperatorOr }
3257 
3258 procedure TFpPascalExpressionPartOperatorOr.Init;
3259 begin
3260   FPrecedence := PRECEDENCE_OR;
3261   inherited Init;
3262 end;
3263 
TFpPascalExpressionPartOperatorOr.DoGetResultValuenull3264 function TFpPascalExpressionPartOperatorOr.DoGetResultValue: TFpValue;
3265 var
3266   tmp1, tmp2: TFpValue;
3267 begin
3268   Result := nil;
3269   if Count <> 2 then exit;
3270 
3271   tmp1 := Items[0].ResultValue;
3272   tmp2 := Items[1].ResultValue;
3273   if (tmp1 = nil) or (tmp2 = nil) then exit;
3274 
3275   {$PUSH}{$R-}{$Q-}
3276   case FOp of
3277     ootOr:
3278     case tmp1.Kind of
3279       skInteger: if tmp2.Kind in [skInteger, skCardinal] then
3280                    Result := TFpValueConstNumber.Create(tmp1.AsInteger OR tmp2.AsInteger, True);
3281       skCardinal: if tmp2.Kind = skInteger then
3282                     Result := TFpValueConstNumber.Create(tmp1.AsInteger OR tmp2.AsInteger, True)
3283                   else
3284                   if tmp2.Kind = skCardinal then
3285                     Result := TFpValueConstNumber.Create(tmp1.AsInteger OR tmp2.AsInteger, False);
3286       skBoolean: if tmp2.Kind = skBoolean then
3287                    Result := TFpValueConstBool.Create(tmp1.AsBool OR tmp2.AsBool);
3288     end;
3289     ootXor:
3290     case tmp1.Kind of
3291       skInteger: if tmp2.Kind in [skInteger, skCardinal] then
3292                    Result := TFpValueConstNumber.Create(tmp1.AsInteger XOR tmp2.AsInteger, True);
3293       skCardinal: if tmp2.Kind = skInteger then
3294                     Result := TFpValueConstNumber.Create(tmp1.AsInteger XOR tmp2.AsInteger, True)
3295                   else
3296                   if tmp2.Kind = skCardinal then
3297                     Result := TFpValueConstNumber.Create(tmp1.AsInteger XOR tmp2.AsInteger, False);
3298       skBoolean: if tmp2.Kind = skBoolean then
3299                    Result := TFpValueConstBool.Create(tmp1.AsBool XOR tmp2.AsBool);
3300     end;
3301   end;
3302   {$POP}
3303 
3304  {$IFDEF WITH_REFCOUNT_DEBUG}if Result <> nil then Result.DbgRenameReference(nil, 'DoGetResultValue');{$ENDIF}
3305 end;
3306 
3307 constructor TFpPascalExpressionPartOperatorOr.Create(
3308   AExpression: TFpPascalExpression; AnOp: TOpOrType; AStartChar: PChar;
3309   AnEndChar: PChar);
3310 begin
3311   inherited Create(AExpression, AStartChar, AnEndChar);
3312   FOp := AnOp;
3313 end;
3314 
3315 { TFpPascalExpressionPartOperatorCompare }
3316 
3317 procedure TFpPascalExpressionPartOperatorCompare.Init;
3318 begin
3319   FPrecedence := PRECEDENCE_COMPARE;
3320   inherited Init;
3321 end;
3322 
TFpPascalExpressionPartOperatorCompare.DoGetResultValuenull3323 function TFpPascalExpressionPartOperatorCompare.DoGetResultValue: TFpValue;
3324 {$PUSH}{$R-}{$Q-}
IntEqualToValuenull3325   function IntEqualToValue(AIntVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
3326   begin
3327     Result := nil;
3328     case AOtherVal.Kind of
3329       skInteger:  Result := TFpValueConstBool.Create((AIntVal.AsInteger = AOtherVal.AsInteger) xor AReverse);
3330       skCardinal: Result := TFpValueConstBool.Create((AIntVal.AsInteger = AOtherVal.AsCardinal) xor AReverse);
3331       skFloat:    Result := TFpValueConstBool.Create((AIntVal.AsInteger = AOtherVal.AsFloat) xor AReverse);
3332       else SetError('= not supported');
3333     end;
3334   end;
CardinalEqualToValuenull3335   function CardinalEqualToValue(ACardinalVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
3336   begin
3337     Result := nil;
3338     case AOtherVal.Kind of
3339       skInteger:  Result := TFpValueConstBool.Create((ACardinalVal.AsCardinal = AOtherVal.AsInteger) xor AReverse);
3340       skCardinal: Result := TFpValueConstBool.Create((ACardinalVal.AsCardinal = AOtherVal.AsCardinal) xor AReverse);
3341       skFloat:    Result := TFpValueConstBool.Create((ACardinalVal.AsCardinal = AOtherVal.AsFloat) xor AReverse);
3342       else SetError('= not supported');
3343     end;
3344   end;
FloatEqualToValuenull3345   function FloatEqualToValue(AFloatVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
3346   begin
3347     Result := nil;
3348     case AOtherVal.Kind of
3349       skInteger:  Result := TFpValueConstBool.Create((AFloatVal.AsFloat = AOtherVal.AsInteger) xor AReverse);
3350       skCardinal: Result := TFpValueConstBool.Create((AFloatVal.AsFloat = AOtherVal.AsCardinal) xor AReverse);
3351       skFloat:    Result := TFpValueConstBool.Create((AFloatVal.AsFloat = AOtherVal.AsFloat) xor AReverse);
3352       else SetError('= not supported');
3353     end;
3354   end;
AddressPtrEqualToValuenull3355   function AddressPtrEqualToValue(AIntVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
3356   begin
3357     Result := nil;
3358     if AOtherVal.Kind in [skClass,skInterface,skAddress,skPointer] then
3359       Result := TFpValueConstBool.Create((AIntVal.AsCardinal = AOtherVal.AsCardinal) xor AReverse)
3360     else
3361       SetError('= not supported');
3362   end;
CharDataEqualToValuenull3363   function CharDataEqualToValue(ACharVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
3364   begin
3365     Result := nil;
3366     if (AOtherVal.FieldFlags * [svfString, svfWideString] <> []) then
3367       Result := TFpValueConstBool.Create((ACharVal.AsString = AOtherVal.AsString) xor AReverse)
3368     else
3369       SetError('= not supported');
3370   end;
3371 
IntGreaterThanValuenull3372   function IntGreaterThanValue(AIntVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
3373   begin
3374     Result := nil;
3375     case AOtherVal.Kind of
3376       skInteger:  Result := TFpValueConstBool.Create((AIntVal.AsInteger > AOtherVal.AsInteger) xor AReverse);
3377       skCardinal: Result := TFpValueConstBool.Create((AIntVal.AsInteger > AOtherVal.AsCardinal) xor AReverse);
3378       skFloat:    Result := TFpValueConstBool.Create((AIntVal.AsInteger > AOtherVal.AsFloat) xor AReverse);
3379       else SetError('= not supported');
3380     end;
3381   end;
CardinalGreaterThanValuenull3382   function CardinalGreaterThanValue(ACardinalVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
3383   begin
3384     Result := nil;
3385     case AOtherVal.Kind of
3386       skInteger:  Result := TFpValueConstBool.Create((ACardinalVal.AsCardinal > AOtherVal.AsInteger) xor AReverse);
3387       skCardinal: Result := TFpValueConstBool.Create((ACardinalVal.AsCardinal > AOtherVal.AsCardinal) xor AReverse);
3388       skFloat:    Result := TFpValueConstBool.Create((ACardinalVal.AsCardinal > AOtherVal.AsFloat) xor AReverse);
3389       else SetError('= not supported');
3390     end;
3391   end;
FloatGreaterThanValuenull3392   function FloatGreaterThanValue(AFloatVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
3393   begin
3394     Result := nil;
3395     case AOtherVal.Kind of
3396       skInteger:  Result := TFpValueConstBool.Create((AFloatVal.AsFloat > AOtherVal.AsInteger) xor AReverse);
3397       skCardinal: Result := TFpValueConstBool.Create((AFloatVal.AsFloat > AOtherVal.AsCardinal) xor AReverse);
3398       skFloat:    Result := TFpValueConstBool.Create((AFloatVal.AsFloat > AOtherVal.AsFloat) xor AReverse);
3399       else SetError('= not supported');
3400     end;
3401   end;
CharDataGreaterThanValuenull3402   function CharDataGreaterThanValue(ACharVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
3403   begin
3404     Result := nil;
3405     if (AOtherVal.FieldFlags * [svfString, svfWideString] <> []) then
3406       Result := TFpValueConstBool.Create((ACharVal.AsString > AOtherVal.AsString) xor AReverse)
3407     else
3408       SetError('= not supported');
3409   end;
3410 
IntSmallerThanValuenull3411   function IntSmallerThanValue(AIntVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
3412   begin
3413     Result := nil;
3414     case AOtherVal.Kind of
3415       skInteger:  Result := TFpValueConstBool.Create((AIntVal.AsInteger < AOtherVal.AsInteger) xor AReverse);
3416       skCardinal: Result := TFpValueConstBool.Create((AIntVal.AsInteger < AOtherVal.AsCardinal) xor AReverse);
3417       skFloat:    Result := TFpValueConstBool.Create((AIntVal.AsInteger < AOtherVal.AsFloat) xor AReverse);
3418       else SetError('= not supported');
3419     end;
3420   end;
CardinalSmallerThanValuenull3421   function CardinalSmallerThanValue(ACardinalVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
3422   begin
3423     Result := nil;
3424     case AOtherVal.Kind of
3425       skInteger:  Result := TFpValueConstBool.Create((ACardinalVal.AsCardinal < AOtherVal.AsInteger) xor AReverse);
3426       skCardinal: Result := TFpValueConstBool.Create((ACardinalVal.AsCardinal < AOtherVal.AsCardinal) xor AReverse);
3427       skFloat:    Result := TFpValueConstBool.Create((ACardinalVal.AsCardinal < AOtherVal.AsFloat) xor AReverse);
3428       else SetError('= not supported');
3429     end;
3430   end;
FloatSmallerThanValuenull3431   function FloatSmallerThanValue(AFloatVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
3432   begin
3433     Result := nil;
3434     case AOtherVal.Kind of
3435       skInteger:  Result := TFpValueConstBool.Create((AFloatVal.AsFloat < AOtherVal.AsInteger) xor AReverse);
3436       skCardinal: Result := TFpValueConstBool.Create((AFloatVal.AsFloat < AOtherVal.AsCardinal) xor AReverse);
3437       skFloat:    Result := TFpValueConstBool.Create((AFloatVal.AsFloat < AOtherVal.AsFloat) xor AReverse);
3438       else SetError('= not supported');
3439     end;
3440   end;
CharDataSmallerThanValuenull3441   function CharDataSmallerThanValue(ACharVal, AOtherVal: TFpValue; AReverse: Boolean = False): TFpValue;
3442   begin
3443     Result := nil;
3444     if (AOtherVal.FieldFlags * [svfString, svfWideString] <> []) then
3445       Result := TFpValueConstBool.Create((ACharVal.AsString < AOtherVal.AsString) xor AReverse)
3446     else
3447       SetError('= not supported');
3448   end;
3449 
3450 {$POP}
3451 var
3452   tmp1, tmp2: TFpValue;
3453   s: String;
3454 begin
3455   Result := nil;
3456   if Count <> 2 then exit;
3457 
3458   tmp1 := Items[0].ResultValue;
3459   tmp2 := Items[1].ResultValue;
3460   if (tmp1 = nil) or (tmp2 = nil) then exit;
3461   s := GetText;
3462 
3463   if (s = '=') or (s = '<>') then begin
3464     case tmp1.Kind of
3465       skInteger:  Result := IntEqualToValue(tmp1, tmp2, (s = '<>'));
3466       skCardinal: Result := CardinalEqualToValue(tmp1, tmp2, (s = '<>'));
3467       skFloat:    Result := FloatEqualToValue(tmp1, tmp2, (s = '<>'));
3468       skPointer: begin
3469                   // Pchar can concatenate with String. But not with other Pchar
3470                   // Maybe allow optional: This does limit undetected/mis-detected strings
3471                   if (tmp1.FieldFlags * [svfString, svfWideString] <> []) and
3472                      (tmp2.Kind in [skString, skAnsiString, skWideString, skChar{, skWideChar}])
3473                   then
3474                     Result := CharDataEqualToValue(tmp1, tmp2, (s = '<>'))
3475                   else
3476                     Result := AddressPtrEqualToValue(tmp1, tmp2, (s = '<>'));
3477         end;
3478       skClass,skInterface:
3479                   Result := AddressPtrEqualToValue(tmp1, tmp2, (s = '<>'));
3480       skAddress: begin
3481                   if tmp2.Kind in [skClass,skInterface,skPointer,skAddress] then
3482                     Result := AddressPtrEqualToValue(tmp1, tmp2, (s = '<>'));
3483         end;
3484       skString, skAnsiString, skWideString, skChar{, skWideChar}:
3485                   Result := CharDataEqualToValue(tmp1, tmp2, (s = '<>'));
3486     end;
3487   end
3488   else
3489   if (s = '>') or (s = '<=') then begin
3490     case tmp1.Kind of
3491       skInteger:  Result := IntGreaterThanValue(tmp1, tmp2, (s = '<='));
3492       skCardinal: Result := CardinalGreaterThanValue(tmp1, tmp2, (s = '<='));
3493       skFloat:    Result := FloatGreaterThanValue(tmp1, tmp2, (s = '<='));
3494       skPointer:  if (tmp1.FieldFlags * [svfString, svfWideString] <> []) and
3495                      (tmp2.Kind in [skString, skAnsiString, skWideString, skChar{, skWideChar}])
3496                    then
3497                      Result := CharDataGreaterThanValue(tmp1, tmp2, (s = '<='));
3498       skString, skAnsiString, skWideString, skChar{, skWideChar}:
3499                   Result := CharDataGreaterThanValue(tmp1, tmp2, (s = '<='));
3500     end;
3501   end
3502   else
3503   if (s = '<') or (s = '>=') then begin
3504     case tmp1.Kind of
3505       skInteger:  Result := IntSmallerThanValue(tmp1, tmp2, (s = '>='));
3506       skCardinal: Result := CardinalSmallerThanValue(tmp1, tmp2, (s = '>='));
3507       skFloat:    Result := FloatSmallerThanValue(tmp1, tmp2, (s = '>='));
3508       skPointer:  if (tmp1.FieldFlags * [svfString, svfWideString] <> []) and
3509                      (tmp2.Kind in [skString, skAnsiString, skWideString, skChar{, skWideChar}])
3510                    then
3511                      Result := CharDataSmallerThanValue(tmp1, tmp2, (s = '>='));
3512       skString, skAnsiString, skWideString, skChar{, skWideChar}:
3513                   Result := CharDataSmallerThanValue(tmp1, tmp2, (s = '>='));
3514     end;
3515   end
3516   else
3517   if GetText = '><' then begin
3518     // compare SET
3519   end;
3520 
3521  {$IFDEF WITH_REFCOUNT_DEBUG}if Result <> nil then
3522    Result.DbgRenameReference(nil, 'DoGetResultValue');{$ENDIF}
3523 end;
3524 
3525 { TFpPascalExpressionPartOperatorMemberOf }
3526 
3527 procedure TFpPascalExpressionPartOperatorMemberOf.Init;
3528 begin
3529   FPrecedence := PRECEDENCE_MEMBER_OF;
3530   inherited Init;
3531 end;
3532 
IsValidNextPartnull3533 function TFpPascalExpressionPartOperatorMemberOf.IsValidNextPart(APart: TFpPascalExpressionPart): Boolean;
3534 begin
3535   Result := inherited IsValidNextPart(APart);
3536   if not HasAllOperands then
3537     Result := Result and (APart is TFpPascalExpressionPartIdentifier);
3538 end;
3539 
TFpPascalExpressionPartOperatorMemberOf.DoGetResultValuenull3540 function TFpPascalExpressionPartOperatorMemberOf.DoGetResultValue: TFpValue;
3541 var
3542   tmp: TFpValue;
3543   MemberName: String;
3544   MemberSym: TFpSymbol;
3545   {$IFDEF FpDebugAutoDerefMember}
3546   tmp2: TFpValue;
3547   {$ENDIF}
3548 begin
3549   Result := nil;
3550   if Count <> 2 then exit;
3551 
3552   tmp := Items[0].ResultValue;
3553   if (tmp = nil) then
3554     exit;
3555 
3556   MemberName := Items[1].GetText;
3557 
3558   {$IFDEF FpDebugAutoDerefMember}
3559   // Copy from TFpPascalExpressionPartOperatorDeRef.DoGetResultValue
3560   tmp2 := nil;
3561   if tmp.Kind = skPointer then begin
3562     if (svfDataAddress in tmp.FieldFlags) and (IsReadableLoc(tmp.DataAddress)) and // TODO, what if Not readable addr
3563        (tmp.TypeInfo <> nil) //and (tmp.TypeInfo.TypeInfo <> nil)
3564     then begin
3565       tmp := tmp.Member[0];
3566       tmp2 := tmp;
3567     end;
3568     if (tmp = nil) then begin
3569       SetError(fpErrCannotDereferenceType, [Items[0].GetText]); // TODO: better error
3570       exit;
3571     end;
3572   end;
3573   {$ENDIF}
3574 
3575   if (tmp.Kind in [skClass, skRecord, skObject]) then begin
3576     Result := tmp.MemberByName[MemberName];
3577     if Result = nil then begin
3578       SetError(fpErrNoMemberWithName, [MemberName]);
3579       exit;
3580     end;
3581     {$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue'){$ENDIF};
3582     Assert((Result.DbgSymbol=nil)or(Result.DbgSymbol.SymbolType=stValue), 'member is value');
3583     exit;
3584   end;
3585   {$IFDEF FpDebugAutoDerefMember}
3586   tmp2.ReleaseReference;
3587   {$ENDIF}
3588 
3589   if (tmp.Kind in [skType]) and
3590      (tmp.DbgSymbol <> nil) and (tmp.DbgSymbol.Kind in [skClass, skRecord, skObject])
3591   then begin
3592     Result := tmp.MemberByName[MemberName];
3593     if Result <> nil then begin
3594       // only class fields/constants can have an address without valid "self" instance
3595       if IsReadableLoc(result.DataAddress) then begin   // result.Address?
3596         {$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue'){$ENDIF};
3597         exit;
3598       end
3599       else begin
3600         ReleaseRefAndNil(Result);
3601         MemberSym := tmp.DbgSymbol.NestedSymbolByName[MemberName];
3602         if MemberSym <> nil then begin
3603           Result := TFpValueTypeDefinition.Create(MemberSym);
3604           {$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue'){$ENDIF};
3605           exit;
3606         end;
3607       end;
3608     end;
3609     SetError(fpErrNoMemberWithName, [MemberName]);
3610     exit
3611   end;
3612 
3613   if (tmp.Kind = skUnit) or
3614      ( (tmp.DbgSymbol <> nil) and (tmp.DbgSymbol.Kind = skUnit) )
3615   then begin
3616     (* If a class/record/object matches the typename, but did not have the member,
3617        then this could still be a unit.
3618        If the class/record/object is in the same unit as the current contexct (selected function)
3619        then it would hide the unitname, but otherwise a unit in the uses clause would
3620        hide the structure.
3621     *)
3622     Result := Expression.FContext.FindSymbol(MemberName, Items[0].GetText);
3623     if Result <> nil then begin
3624       {$IFDEF WITH_REFCOUNT_DEBUG}Result.DbgRenameReference(nil, 'DoGetResultValue'){$ENDIF};
3625       exit;
3626     end;
3627   end;
3628 
3629 
3630   SetError(fpErrorNotAStructure, [MemberName, Items[0].GetText]);
3631 end;
3632 
3633 end.
3634 
3635