1 {*********************************************************}
3 { Zeos Database Objects }
4 { Expression classes and interfaces }
6 { Originally written by Sergey Seroukhov }
8 {*********************************************************}
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
13 { License Agreement: }
15 { This library is distributed in the hope that it will be }
16 { useful, but WITHOUT ANY WARRANTY; without even the }
17 { implied warranty of MERCHANTABILITY or FITNESS FOR }
18 { A PARTICULAR PURPOSE. See the GNU Lesser General }
19 { Public License for more details. }
21 { The source code of the ZEOS Libraries and packages are }
22 { distributed under the Library GNU General Public }
23 { License (see the file COPYING / COPYING.ZEOS) }
24 { with the following modification: }
25 { As a special exception, the copyright holders of this }
26 { library give you permission to link this library with }
27 { independent modules to produce an executable, }
28 { regardless of the license terms of these independent }
29 { modules, and to copy and distribute the resulting }
30 { executable under terms of your choice, provided that }
31 { you also meet, for each linked independent module, }
32 { the terms and conditions of the license of that module. }
33 { An independent module is a module which is not derived }
34 { from or based on this library. If you modify this }
35 { library, you may extend this exception to your version }
36 { of the library, but you are not obligated to do so. }
37 { If you do not wish to do so, delete this exception }
38 { statement from your version. }
41 { The project web site is located on: }
42 { http://zeos.firmos.at (FORUM) }
43 { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
44 { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) }
46 { http://www.sourceforge.net/projects/zeoslib. }
49 { Zeos Development Group. }
50 {********************************************************@}
58 uses SysUtils, Classes, {$IFDEF WITH_TOBJECTLIST_INLINE}System.Contnrs, {$ENDIF}
59 ZClasses, ZCompatibility, ZVariant, ZTokenizer, ZExprParser;
62 {** Defines an expression exception. }
63 TZExpressionError = class (Exception);
65 {** Defines an execution stack object. }
66 TZExecutionStack = class (TObject)
68 FValues: TZVariantDynArray;
72 function GetValue(Index: Integer): TZVariant;
76 procedure DecStackPointer(const Value : integer);
77 function Pop: TZVariant;
78 function Peek: TZVariant;
79 procedure Push(Value: TZVariant);
80 function GetParameter(Index: Integer): TZVariant;
85 property Count: Integer read FCount;
86 property Values[Index: Integer]: TZVariant read GetValue;
89 {** Defines a list of variables. }
90 IZVariablesList = interface (IZInterface)
91 ['{F4347F46-32F3-4021-B6DB-7A39BF171275}']
93 function GetCount: Integer;
94 function GetName(Index: Integer): string;
95 function GetValue(Index: Integer): TZVariant;
96 procedure SetValue(Index: Integer; const Value: TZVariant);
97 function GetValueByName(const Name: string): TZVariant;
98 procedure SetValueByName(const Name: string; const Value: TZVariant);
100 procedure Add(const Name: string; const Value: TZVariant);
101 procedure Remove(const Name: string);
102 function FindByName(const Name: string): Integer;
104 procedure ClearValues;
107 property Count: Integer read GetCount;
108 property Names[Index: Integer]: string read GetName;
109 property Values[Index: Integer]: TZVariant read GetValue write SetValue;
110 property NamedValues[const Index: string]: TZVariant read GetValueByName
111 write SetValueByName;
114 {** Defines a function interface. }
115 IZFunction = interface (IZInterface)
116 ['{E9B3AFF9-6CD9-49C8-AB66-C8CF60ED8686}']
118 function GetName: string;
120 function Execute(Stack: TZExecutionStack;
121 VariantManager: IZVariantManager): TZVariant;
123 property Name: string read GetName;
126 {** Defines a list of functions. }
127 IZFunctionsList = interface (IZInterface)
128 ['{54453054-F012-475B-84C3-7E5C46187FDB}']
130 function GetCount: Integer;
131 function GetName(Index: Integer): string;
132 function GetFunction(Index: Integer): IZFunction;
134 procedure Add(Func: IZFunction);
135 procedure Remove(const Name: string);
136 function FindByName(const Name: string): Integer;
139 property Count: Integer read GetCount;
140 property Names[Index: Integer]: string read GetName;
141 property Functions[Index: Integer]: IZFunction read GetFunction;
144 {** Defines an interface to expression calculator. }
145 IZExpression = interface (IZInterface)
146 ['{26F9D379-5618-446C-8999-D50FBB2F8560}']
148 function GetTokenizer: IZTokenizer;
149 procedure SetTokenizer(Value: IZTokenizer);
150 function GetExpression: string;
151 procedure SetExpression(const Value: string);
152 function GetVariantManager: IZVariantManager;
153 procedure SetVariantManager(Value: IZVariantManager);
154 function GetDefaultVariables: IZVariablesList;
155 procedure SetDefaultVariables(Value: IZVariablesList);
156 function GetDefaultFunctions: IZFunctionsList;
157 procedure SetDefaultFunctions(Value: IZFunctionsList);
158 function GetAutoVariables: Boolean;
159 procedure SetAutoVariables(Value: Boolean);
161 function Evaluate: TZVariant;
162 function Evaluate2(Variables: IZVariablesList): TZVariant;
163 function Evaluate3(Variables: IZVariablesList;
164 Functions: IZFunctionsList): TZVariant;
165 function Evaluate4(Variables: IZVariablesList;
166 Functions: IZFunctionsList; Stack: TZExecutionStack): TZVariant;
168 procedure CreateVariables(Variables: IZVariablesList);
171 property Tokenizer: IZTokenizer read GetTokenizer write SetTokenizer;
172 property Expression: string read GetExpression write SetExpression;
173 property VariantManager: IZVariantManager read GetVariantManager
174 write SetVariantManager;
175 property DefaultVariables: IZVariablesList read GetDefaultVariables
176 write SetDefaultVariables;
177 property DefaultFunctions: IZFunctionsList read GetDefaultFunctions
178 write SetDefaultFunctions;
179 property AutoVariables: Boolean read GetAutoVariables
180 write SetAutoVariables;
183 {** Implements an expression calculator class. }
184 TZExpression = class (TInterfacedObject, IZExpression)
186 FTokenizer: IZTokenizer;
187 FDefaultVariables: IZVariablesList;
188 FDefaultFunctions: IZFunctionsList;
189 FVariantManager: IZVariantManager;
190 FParser: TZExpressionParser;
191 FAutoVariables: Boolean;
193 function GetTokenizer: IZTokenizer;
194 procedure SetTokenizer(Value: IZTokenizer);
195 function GetExpression: string;
196 procedure SetExpression(const Value: string);
197 function GetVariantManager: IZVariantManager;
198 procedure SetVariantManager(Value: IZVariantManager);
199 function GetDefaultVariables: IZVariablesList;
200 procedure SetDefaultVariables(Value: IZVariablesList);
201 function GetDefaultFunctions: IZFunctionsList;
202 procedure SetDefaultFunctions(Value: IZFunctionsList);
203 function GetAutoVariables: Boolean;
204 procedure SetAutoVariables(Value: Boolean);
207 constructor CreateWithExpression(const Expression: string);
208 destructor Destroy; override;
210 function Evaluate: TZVariant;
211 function Evaluate2(Variables: IZVariablesList): TZVariant;
212 function Evaluate3(Variables: IZVariablesList;
213 Functions: IZFunctionsList): TZVariant;
214 function Evaluate4(Variables: IZVariablesList;
215 Functions: IZFunctionsList; Stack: TZExecutionStack): TZVariant;
217 procedure CreateVariables(Variables: IZVariablesList);
220 property Expression: string read GetExpression write SetExpression;
221 property VariantManager: IZVariantManager read GetVariantManager
222 write SetVariantManager;
223 property DefaultVariables: IZVariablesList read GetDefaultVariables
224 write SetDefaultVariables;
225 property DefaultFunctions: IZFunctionsList read GetDefaultFunctions
226 write SetDefaultFunctions;
227 property AutoVariables: Boolean read GetAutoVariables
228 write SetAutoVariables;
234 ZMessages, ZExprToken, ZVariables, ZFunctions, ZMatchPattern;
241 constructor TZExecutionStack.Create;
244 SetLength(FValues, FCapacity);
249 Gets a value from absolute position in the stack.
250 @param Index a value index.
251 @returns a variant value from requested position.
253 function TZExecutionStack.GetValue(Index: Integer): TZVariant;
255 Result := FValues[Index];
259 Gets a value from the top of the stack without removing it.
260 @returns a value from the top.
262 function TZExecutionStack.Peek: TZVariant;
265 Result := FValues[FCount - 1]
266 else Result := NullVariant;
270 Gets a function parameter by index.
271 @param a function parameter index. O is used for parameter count.
272 @returns a parameter value.
274 function TZExecutionStack.GetParameter(Index: Integer): TZVariant;
276 if FCount <= Index then
277 raise TZExpressionError.Create(SStackIsEmpty);
278 Result := FValues[FCount - Index - 1];
281 procedure TZExecutionStack.DecStackPointer(const Value : integer);
287 raise TZExpressionError.Create(SStackIsEmpty);
292 Gets a value from the top and removes it from the stack.
293 @returns a value from the top.
295 function TZExecutionStack.Pop: TZVariant;
297 Result := NullVariant;
299 raise TZExpressionError.Create(SStackIsEmpty);
301 Result := FValues[FCount];
305 Puts a value to the top of the stack.
307 procedure TZExecutionStack.Push(Value: TZVariant);
309 if FCapacity = FCount then
312 SetLength(FValues, FCapacity);
314 DefVarManager.Assign(Value, FValues[FCount]);
319 Swaps two values on the top of the stack.
321 procedure TZExecutionStack.Swap;
326 raise TZExpressionError.Create(SStackIsEmpty);
328 Temp := FValues[FCount - 1];
329 FValues[FCount - 1] := FValues[FCount - 2];
330 FValues[FCount - 2] := Temp;
336 procedure TZExecutionStack.Clear;
344 Creates this expression calculator object.
346 constructor TZExpression.Create;
348 FTokenizer := TZExpressionTokenizer.Create;
349 FDefaultVariables := TZVariablesList.Create;
350 FDefaultFunctions := TZDefaultFunctionsList.Create;
351 FVariantManager := TZSoftVariantManager.Create;
352 FParser := TZExpressionParser.Create(FTokenizer);
353 FAutoVariables := True;
357 Creates this expression calculator and assignes expression string.
358 @param Expression an expression string.
360 constructor TZExpression.CreateWithExpression(const Expression: string);
363 SetExpression(Expression);
367 Destroys this object and cleanups the memory.
369 destructor TZExpression.Destroy;
372 FDefaultVariables := nil;
373 FDefaultFunctions := nil;
374 FVariantManager := nil;
381 Gets the current auto variables create flag.
382 @returns the auto variables create flag.
384 function TZExpression.GetAutoVariables: Boolean;
386 Result := FAutoVariables;
390 Sets a new auto variables create flag.
391 @param value a new auto variables create flag.
393 procedure TZExpression.SetAutoVariables(Value: Boolean);
395 FAutoVariables := Value;
399 Gets a list of default functions.
400 @returns a list of default functions.
402 function TZExpression.GetDefaultFunctions: IZFunctionsList;
404 Result := FDefaultFunctions;
408 Sets a new list of functions.
409 @param Value a new list of functions.
411 procedure TZExpression.SetDefaultFunctions(Value: IZFunctionsList);
413 FDefaultFunctions := Value;
417 Gets a list of default variables.
418 @returns a list of default variables.
420 function TZExpression.GetDefaultVariables: IZVariablesList;
422 Result := FDefaultVariables;
426 Sets a new list of variables.
427 @param Value a new list of variables.
429 procedure TZExpression.SetDefaultVariables(Value: IZVariablesList);
431 FDefaultVariables := Value;
435 Gets the current set expression string.
436 @returns the current expression string.
438 function TZExpression.GetExpression: string;
440 Result := FParser.Expression;
444 Sets a new expression string.
445 @param Value a new expression string.
447 procedure TZExpression.SetExpression(const Value: string);
449 FParser.Expression := Value;
450 if FAutoVariables then
451 CreateVariables(FDefaultVariables);
455 Gets a reference to the current variant manager.
456 @returns a reference to the current variant manager.
458 function TZExpression.GetVariantManager: IZVariantManager;
460 Result := FVariantManager;
464 Sets a new variant manager.
465 @param Value a new variant manager.
467 procedure TZExpression.SetVariantManager(Value: IZVariantManager);
469 FVariantManager := Value;
473 Gets the current expression tokenizer.
474 @returns the current expression tokenizer.
476 function TZExpression.GetTokenizer: IZTokenizer;
478 Result := FTokenizer;
482 Sets a new expression tokenizer.
483 @param Value a new expression tokenizer.
485 procedure TZExpression.SetTokenizer(Value: IZTokenizer);
488 FParser.Tokenizer := Value;
492 Clears this class from all data.
494 procedure TZExpression.Clear;
497 FDefaultVariables.Clear;
501 Creates an empty variables.
502 @param Variables a list of variables.
504 procedure TZExpression.CreateVariables(Variables: IZVariablesList);
509 for I := 0 to FParser.Variables.Count - 1 do
511 Name := FParser.Variables[I];
512 if Variables.FindByName(Name) < 0 then
513 Variables.Add(Name, NullVariant);
518 Evaluates this expression.
519 @returns an evaluated expression value.
521 function TZExpression.Evaluate: TZVariant;
523 Result := Evaluate3(FDefaultVariables, FDefaultFunctions);
527 Evaluates this expression.
528 @param Variables a list of variables.
529 @returns an evaluated expression value.
531 function TZExpression.Evaluate2(Variables: IZVariablesList): TZVariant;
533 Result := Evaluate3(Variables, FDefaultFunctions);
537 Evaluates this expression.
538 @param Variables a list of variables.
539 @param Functions a list of functions.
540 @returns an evaluated expression value.
542 function TZExpression.Evaluate3(Variables: IZVariablesList;
543 Functions: IZFunctionsList): TZVariant;
545 Stack: TZExecutionStack;
547 Stack := TZExecutionStack.Create;
549 Result := Evaluate4(Variables, Functions, Stack);
556 Evaluates this expression.
557 @param Variables a list of variables.
558 @param Functions a list of functions.
559 @param Stack an execution stack.
560 @returns an evaluated expression value.
562 function TZExpression.Evaluate4(Variables: IZVariablesList;
563 Functions: IZFunctionsList; Stack: TZExecutionStack): TZVariant;
565 I, Index, ParamsCount: Integer;
566 Current: TZExpressionToken;
567 Value1, Value2: TZVariant;
571 for I := 0 to FParser.ResultTokens.Count - 1 do
573 Current := TZExpressionToken(FParser.ResultTokens[I]);
574 case Current.TokenType of
576 Stack.Push(Current.Value);
579 Index := Variables.FindByName(DefVarManager.GetAsString(Current.Value));
582 raise TZExpressionError.Create(
583 Format(SVariableWasNotFound, [DefVarManager.GetAsString(Current.Value)]));
585 Value1 := Variables.Values[Index];
590 if Current.Value.VType = vtString then
592 Index := Variables.FindByName(Current.Value.VString);
595 raise TZExpressionError.Create(
596 Format(SVariableWasNotFound, [Current.Value.VString]));
598 Current.Value := EncodeInteger(Index);
600 if Current.Value.VType = vtInteger then
601 Stack.Push(Variables.Values[Current.Value.VInteger])
603 raise TZExpressionError.Create(
604 Format(SSyntaxErrorNear, [SoftVarManager.GetAsString(Current.Value)]));
608 Index := Functions.FindByName(DefVarManager.GetAsString(Current.Value));
611 raise TZExpressionError.Create(
612 Format(SFunctionWasNotFound, [DefVarManager.GetAsString(Current.Value)]));
614 Value1 := Functions.Functions[Index].Execute(Stack, FVariantManager);
615 ParamsCount := DefVarManager.GetAsInteger(Stack.Pop);
616 while ParamsCount > 0 do
625 if Current.Value.VType = vtString then
627 Index := Functions.FindByName(Current.Value.VString);
630 raise TZExpressionError.Create(
631 Format(SFunctionWasNotFound, [Current.Value.VString]));
633 Current.Value := EncodeInterface(Functions.Functions[Index]);
635 if Current.Value.VType = vtInterface then
637 Value1 := IZFunction(Current.Value.VInterface).Execute(Stack, FVariantManager);
638 ParamsCount := DefVarManager.GetAsInteger(Stack.Pop);
639 Stack.DecStackPointer(ParamsCount);
643 raise TZExpressionError.Create(
644 Format(SSyntaxErrorNear, [SoftVarManager.GetAsString(Current.Value)]));
650 Stack.Push(FVariantManager.OpAnd(Value1, Value2));
656 Stack.Push(FVariantManager.OpOr(Value1, Value2));
662 Stack.Push(FVariantManager.OpXor(Value1, Value2));
665 Stack.Push(FVariantManager.OpNot(Stack.Pop));
670 Stack.Push(FVariantManager.OpAdd(Value1, Value2));
676 Stack.Push(FVariantManager.OpSub(Value1, Value2));
682 Stack.Push(FVariantManager.OpMul(Value1, Value2));
688 Stack.Push(FVariantManager.OpDiv(Value1, Value2));
694 Stack.Push(FVariantManager.OpMod(Value1, Value2));
700 Stack.Push(FVariantManager.OpEqual(Value1, Value2));
706 Stack.Push(FVariantManager.OpNotEqual(Value1, Value2));
712 Stack.Push(FVariantManager.OpMore(Value1, Value2));
718 Stack.Push(FVariantManager.OpLess(Value1, Value2));
724 Stack.Push(FVariantManager.OpMoreEqual(Value1, Value2));
730 Stack.Push(FVariantManager.OpLessEqual(Value1, Value2));
736 Stack.Push(FVariantManager.OpPow(Value1, Value2));
739 Stack.Push(FVariantManager.OpNegative(Stack.Pop));
744 Stack.Push(EncodeBoolean(
745 IsMatch(FVariantManager.GetAsString(Value2),
746 FVariantManager.GetAsString(Value1))));
752 Stack.Push(EncodeBoolean(
753 not IsMatch(FVariantManager.GetAsString(Value2),
754 FVariantManager.GetAsString(Value1))));
759 Stack.Push(EncodeBoolean(FVariantManager.IsNull(Value1)));
764 Stack.Push(EncodeBoolean(not FVariantManager.IsNull(Value1)));
767 raise TZExpressionError.Create(SInternalError);
771 if Stack.Count <> 1 then
772 raise TZExpressionError.Create(SInternalError);