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