]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Common/RangeExpression.py
2 # This file is used to parse and evaluate range expression in Pcd declaration.
4 # Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 from Common
.GlobalData
import *
16 from CommonDataClass
.Exceptions
import BadExpression
17 from CommonDataClass
.Exceptions
import WrnExpression
20 ERR_STRING_EXPR
= 'This operator cannot be used in string expression: [%s].'
21 ERR_SNYTAX
= 'Syntax error, the rest of expression cannot be evaluated: [%s].'
22 ERR_MATCH
= 'No matching right parenthesis.'
23 ERR_STRING_TOKEN
= 'Bad string token: [%s].'
24 ERR_MACRO_TOKEN
= 'Bad macro token: [%s].'
25 ERR_EMPTY_TOKEN
= 'Empty token is not allowed.'
26 ERR_PCD_RESOLVE
= 'PCD token cannot be resolved: [%s].'
27 ERR_VALID_TOKEN
= 'No more valid token found from rest of string: [%s].'
28 ERR_EXPR_TYPE
= 'Different types found in expression.'
29 ERR_OPERATOR_UNSUPPORT
= 'Unsupported operator: [%s]'
30 ERR_REL_NOT_IN
= 'Expect "IN" after "not" operator.'
31 WRN_BOOL_EXPR
= 'Operand of boolean type cannot be used in arithmetic expression.'
32 WRN_EQCMP_STR_OTHERS
= '== Comparison between Operand of string type and Boolean/Number Type always return False.'
33 WRN_NECMP_STR_OTHERS
= '!= Comparison between Operand of string type and Boolean/Number Type always return True.'
34 ERR_RELCMP_STR_OTHERS
= 'Operator taking Operand of string type and Boolean/Number Type is not allowed: [%s].'
35 ERR_STRING_CMP
= 'Unicode string and general string cannot be compared: [%s %s %s]'
36 ERR_ARRAY_TOKEN
= 'Bad C array or C format GUID token: [%s].'
37 ERR_ARRAY_ELE
= 'This must be HEX value for NList or Array: [%s].'
38 ERR_EMPTY_EXPR
= 'Empty expression is not allowed.'
39 ERR_IN_OPERAND
= 'Macro after IN operator can only be: $(FAMILY), $(ARCH), $(TOOL_CHAIN_TAG) and $(TARGET).'
41 def MaxOfType(DataType
):
42 if DataType
== 'UINT8':
43 return int('0xFF', 16)
44 if DataType
== 'UINT16':
45 return int('0xFFFF', 16)
46 if DataType
== 'UINT32':
47 return int('0xFFFFFFFF', 16)
48 if DataType
== 'UINT64':
49 return int('0xFFFFFFFFFFFFFFFF', 16)
51 class RangeObject(object):
52 def __init__(self
, start
, end
, empty
= False):
54 if int(start
) < int(end
):
55 self
.start
= int(start
)
62 class RangeContainer(object):
66 def push(self
, RangeObject
):
67 self
.rangelist
.append(RangeObject
)
68 self
.rangelist
= sorted(self
.rangelist
, key
= lambda rangeobj
: rangeobj
.start
)
72 for item
in self
.rangelist
:
77 for rangeobj
in self
.rangelist
:
78 if rangeobj
.empty
== True:
81 newrangelist
.append(rangeobj
)
82 self
.rangelist
= newrangelist
85 for i
in range(0, len(self
.rangelist
) - 1):
86 if self
.rangelist
[i
+ 1].start
> self
.rangelist
[i
].end
:
89 self
.rangelist
[i
+ 1].start
= self
.rangelist
[i
].start
90 self
.rangelist
[i
+ 1].end
= self
.rangelist
[i
+ 1].end
> self
.rangelist
[i
].end
and self
.rangelist
[i
+ 1].end
or self
.rangelist
[i
].end
91 self
.rangelist
[i
].empty
= True
96 print "----------------------"
98 for object in self
.rangelist
:
99 rangelist
= rangelist
+ "[%d , %d]" % (object.start
, object.end
)
103 class XOROperatorObject(object):
106 def Calculate(self
, Operand
, DataType
, SymbolTable
):
107 if type(Operand
) == type('') and not Operand
.isalnum():
109 raise BadExpression(ERR_SNYTAX
% Expr
)
110 rangeId
= str(uuid
.uuid1())
111 rangeContainer
= RangeContainer()
112 rangeContainer
.push(RangeObject(0, int(Operand
) - 1))
113 rangeContainer
.push(RangeObject(int(Operand
) + 1, MaxOfType(DataType
)))
114 SymbolTable
[rangeId
] = rangeContainer
117 class LEOperatorObject(object):
120 def Calculate(self
, Operand
, DataType
, SymbolTable
):
121 if type(Operand
) == type('') and not Operand
.isalnum():
123 raise BadExpression(ERR_SNYTAX
% Expr
)
124 rangeId1
= str(uuid
.uuid1())
125 rangeContainer
= RangeContainer()
126 rangeContainer
.push(RangeObject(0, int(Operand
)))
127 SymbolTable
[rangeId1
] = rangeContainer
129 class LTOperatorObject(object):
132 def Calculate(self
, Operand
, DataType
, SymbolTable
):
133 if type(Operand
) == type('') and not Operand
.isalnum():
135 raise BadExpression(ERR_SNYTAX
% Expr
)
136 rangeId1
= str(uuid
.uuid1())
137 rangeContainer
= RangeContainer()
138 rangeContainer
.push(RangeObject(0, int(Operand
) - 1))
139 SymbolTable
[rangeId1
] = rangeContainer
142 class GEOperatorObject(object):
145 def Calculate(self
, Operand
, DataType
, SymbolTable
):
146 if type(Operand
) == type('') and not Operand
.isalnum():
148 raise BadExpression(ERR_SNYTAX
% Expr
)
149 rangeId1
= str(uuid
.uuid1())
150 rangeContainer
= RangeContainer()
151 rangeContainer
.push(RangeObject(int(Operand
), MaxOfType(DataType
)))
152 SymbolTable
[rangeId1
] = rangeContainer
155 class GTOperatorObject(object):
158 def Calculate(self
, Operand
, DataType
, SymbolTable
):
159 if type(Operand
) == type('') and not Operand
.isalnum():
161 raise BadExpression(ERR_SNYTAX
% Expr
)
162 rangeId1
= str(uuid
.uuid1())
163 rangeContainer
= RangeContainer()
164 rangeContainer
.push(RangeObject(int(Operand
) + 1, MaxOfType(DataType
)))
165 SymbolTable
[rangeId1
] = rangeContainer
168 class EQOperatorObject(object):
171 def Calculate(self
, Operand
, DataType
, SymbolTable
):
172 if type(Operand
) == type('') and not Operand
.isalnum():
174 raise BadExpression(ERR_SNYTAX
% Expr
)
175 rangeId1
= str(uuid
.uuid1())
176 rangeContainer
= RangeContainer()
177 rangeContainer
.push(RangeObject(int(Operand
) , int(Operand
)))
178 SymbolTable
[rangeId1
] = rangeContainer
181 def GetOperatorObject(Operator
):
183 return GTOperatorObject()
184 elif Operator
== '>=':
185 return GEOperatorObject()
186 elif Operator
== '<':
187 return LTOperatorObject()
188 elif Operator
== '<=':
189 return LEOperatorObject()
190 elif Operator
== '==':
191 return EQOperatorObject()
192 elif Operator
== '^':
193 return XOROperatorObject()
195 raise BadExpression("Bad Operator")
197 class RangeExpression(object):
198 # Logical operator mapping
200 '&&' : 'and', '||' : 'or',
201 '!' : 'not', 'AND': 'and',
202 'OR' : 'or' , 'NOT': 'not',
203 'XOR': '^' , 'xor': '^',
204 'EQ' : '==' , 'NE' : '!=',
205 'GT' : '>' , 'LT' : '<',
206 'GE' : '>=' , 'LE' : '<=',
210 NonLetterOpLst
= ['+', '-', '&', '|', '^', '!', '=', '>', '<']
212 PcdPattern
= re
.compile(r
'[_a-zA-Z][0-9A-Za-z_]*\.[_a-zA-Z][0-9A-Za-z_]*$')
213 HexPattern
= re
.compile(r
'0[xX][0-9a-fA-F]+')
214 RegGuidPattern
= re
.compile(r
'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}')
215 ExRegGuidPattern
= re
.compile(r
'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')
217 SymbolPattern
= re
.compile("("
218 "\$\([A-Z][A-Z0-9_]*\)|\$\(\w+\.\w+\)|\w+\.\w+|"
220 "(?<=\W)AND(?=\W)|(?<=\W)OR(?=\W)|(?<=\W)NOT(?=\W)|(?<=\W)XOR(?=\W)|"
221 "(?<=\W)EQ(?=\W)|(?<=\W)NE(?=\W)|(?<=\W)GT(?=\W)|(?<=\W)LT(?=\W)|(?<=\W)GE(?=\W)|(?<=\W)LE(?=\W)"
224 RangePattern
= re
.compile(r
'[0-9]+ - [0-9]+')
226 def preProcessRangeExpr(self
, expr
):
228 # convert interval to object index. ex. 1 - 10 to a GUID
231 for HexNumber
in self
.HexPattern
.findall(expr
):
232 Number
= str(int(HexNumber
, 16))
233 NumberDict
[HexNumber
] = Number
234 for HexNum
in NumberDict
:
235 expr
= expr
.replace(HexNum
, NumberDict
[HexNum
])
238 for validrange
in self
.RangePattern
.findall(expr
):
239 start
, end
= validrange
.split(" - ")
240 start
= start
.strip()
242 rangeid
= str(uuid
.uuid1())
243 rangeContainer
= RangeContainer()
244 rangeContainer
.push(RangeObject(start
, end
))
245 self
.operanddict
[str(rangeid
)] = rangeContainer
246 rangedict
[validrange
] = str(rangeid
)
248 for validrange
in rangedict
:
249 expr
= expr
.replace(validrange
, rangedict
[validrange
])
255 def EvalRange(self
, Operator
, Oprand
):
257 operatorobj
= GetOperatorObject(Operator
)
258 return operatorobj
.Calculate(Oprand
, self
.PcdDataType
, self
.operanddict
)
260 def Rangeintersection(self
, Oprand1
, Oprand2
):
261 rangeContainer1
= self
.operanddict
[Oprand1
]
262 rangeContainer2
= self
.operanddict
[Oprand2
]
263 rangeContainer
= RangeContainer()
264 for range1
in rangeContainer1
.pop():
265 for range2
in rangeContainer2
.pop():
266 start1
= range1
.start
268 start2
= range2
.start
271 start1
, start2
= start2
, start1
272 end1
, end2
= end2
, end1
274 rangeid
= str(uuid
.uuid1())
275 rangeContainer
.push(RangeObject(0, 0, True))
277 rangeid
= str(uuid
.uuid1())
278 rangeContainer
.push(RangeObject(0, 0, True))
280 rangeid
= str(uuid
.uuid1())
281 rangeContainer
.push(RangeObject(end1
, end1
))
282 elif end1
<= end2
and end1
> start2
:
283 rangeid
= str(uuid
.uuid1())
284 rangeContainer
.push(RangeObject(start2
, end1
))
286 rangeid
= str(uuid
.uuid1())
287 rangeContainer
.push(RangeObject(start2
, end2
))
289 self
.operanddict
[rangeid
] = rangeContainer
290 # rangeContainer.dump()
293 def Rangecollections(self
, Oprand1
, Oprand2
):
295 rangeContainer1
= self
.operanddict
[Oprand1
]
296 rangeContainer2
= self
.operanddict
[Oprand2
]
297 rangeContainer
= RangeContainer()
299 for rangeobj
in rangeContainer2
.pop():
300 rangeContainer
.push(rangeobj
)
301 for rangeobj
in rangeContainer1
.pop():
302 rangeContainer
.push(rangeobj
)
304 rangeid
= str(uuid
.uuid1())
305 self
.operanddict
[rangeid
] = rangeContainer
307 # rangeContainer.dump()
311 def NegtiveRange(self
, Oprand1
):
312 rangeContainer1
= self
.operanddict
[Oprand1
]
317 for rangeobj
in rangeContainer1
.pop():
318 rangeContainer
= RangeContainer()
319 rangeid
= str(uuid
.uuid1())
321 rangeContainer
.push(RangeObject(0, MaxOfType(self
.PcdDataType
)))
323 if rangeobj
.start
> 0:
324 rangeContainer
.push(RangeObject(0, rangeobj
.start
- 1))
325 if rangeobj
.end
< MaxOfType(self
.PcdDataType
):
326 rangeContainer
.push(RangeObject(rangeobj
.end
+ 1, MaxOfType(self
.PcdDataType
)))
327 self
.operanddict
[rangeid
] = rangeContainer
328 rangeids
.append(rangeid
)
330 if len(rangeids
) == 0:
331 rangeContainer
= RangeContainer()
332 rangeContainer
.push(RangeObject(0, MaxOfType(self
.PcdDataType
)))
333 rangeid
= str(uuid
.uuid1())
334 self
.operanddict
[rangeid
] = rangeContainer
337 if len(rangeids
) == 1:
340 re
= self
.Rangeintersection(rangeids
[0], rangeids
[1])
341 for i
in range(2, len(rangeids
)):
342 re
= self
.Rangeintersection(re
, rangeids
[i
])
344 rangeid2
= str(uuid
.uuid1())
345 self
.operanddict
[rangeid2
] = self
.operanddict
[re
]
348 def Eval(self
, Operator
, Oprand1
, Oprand2
= None):
350 if Operator
in ["!", "NOT", "not"]:
351 if not self
.RegGuidPattern
.match(Oprand1
.strip()):
352 raise BadExpression(ERR_STRING_EXPR
% Operator
)
353 return self
.NegtiveRange(Oprand1
)
355 if Operator
in ["==", ">=", "<=", ">", "<", '^']:
356 return self
.EvalRange(Operator
, Oprand1
)
357 elif Operator
== 'and' :
358 if not self
.ExRegGuidPattern
.match(Oprand1
.strip()) or not self
.ExRegGuidPattern
.match(Oprand2
.strip()):
359 raise BadExpression(ERR_STRING_EXPR
% Operator
)
360 return self
.Rangeintersection(Oprand1
, Oprand2
)
361 elif Operator
== 'or':
362 if not self
.ExRegGuidPattern
.match(Oprand1
.strip()) or not self
.ExRegGuidPattern
.match(Oprand2
.strip()):
363 raise BadExpression(ERR_STRING_EXPR
% Operator
)
364 return self
.Rangecollections(Oprand1
, Oprand2
)
366 raise BadExpression(ERR_STRING_EXPR
% Operator
)
369 def __init__(self
, Expression
, PcdDataType
, SymbolTable
= {}):
370 self
._NoProcess
= False
371 if type(Expression
) != type(''):
372 self
._Expr
= Expression
373 self
._NoProcess
= True
376 self
._Expr
= Expression
.strip()
378 if not self
._Expr
.strip():
379 raise BadExpression(ERR_EMPTY_EXPR
)
382 # The symbol table including PCD and macro mapping
384 self
._Symb
= SymbolTable
385 self
._Symb
.update(self
.LogicalOperators
)
387 self
._Len
= len(self
._Expr
)
389 self
._WarnExcept
= None
392 # Literal token without any conversion
393 self
._LiteralToken
= ''
395 # store the operand object
396 self
.operanddict
= {}
397 # The Pcd max value depends on PcdDataType
398 self
.PcdDataType
= PcdDataType
400 # Public entry for this class
401 # @param RealValue: False: only evaluate if the expression is true or false, used for conditional expression
402 # True : return the evaluated str(value), used for PCD value
404 # @return: True or False if RealValue is False
405 # Evaluated value of string format if RealValue is True
407 def __call__(self
, RealValue
= False, Depth
= 0):
413 self
._Expr
= self
._Expr
.strip()
415 self
.preProcessRangeExpr(self
._Expr
)
417 # check if the expression does not need to evaluate
418 if RealValue
and Depth
== 0:
419 self
._Token
= self
._Expr
420 if self
.ExRegGuidPattern
.match(self
._Expr
):
421 return [self
.operanddict
[self
._Expr
] ]
429 RangeIdList
= RealVal
.split("or")
431 for rangeid
in RangeIdList
:
432 RangeList
.append(self
.operanddict
[rangeid
.strip()])
436 # Template function to parse binary operators which have same precedence
437 # Expr [Operator Expr]*
438 def _ExprFuncTemplate(self
, EvalFunc
, OpLst
):
440 while self
._IsOperator
(OpLst
):
443 Val
= self
.Eval(Op
, Val
, EvalFunc())
444 except WrnExpression
, Warn
:
445 self
._WarnExcept
= Warn
451 return self
._ExprFuncTemplate
(self
._AndExpr
, ["OR", "or"])
455 return self
._ExprFuncTemplate
(self
._NeExpr
, ["AND", "and"])
458 Val
= self
._RelExpr
()
459 while self
._IsOperator
([ "!=", "NOT", "not"]):
461 if Op
in ["!", "NOT", "not"]:
462 if not self
._IsOperator
(["IN", "in"]):
463 raise BadExpression(ERR_REL_NOT_IN
)
464 Op
+= ' ' + self
._Token
466 Val
= self
.Eval(Op
, Val
, self
._RelExpr
())
467 except WrnExpression
, Warn
:
468 self
._WarnExcept
= Warn
474 if self
._IsOperator
(["NOT" , "LE", "GE", "LT", "GT", "EQ", "XOR"]):
478 return self
.Eval(Token
, Val
)
479 except WrnExpression
, Warn
:
480 self
._WarnExcept
= Warn
482 return self
._IdenExpr
()
484 # Parse identifier or encapsulated expression
486 Tk
= self
._GetToken
()
490 # _GetToken may also raise BadExpression
491 if self
._GetToken
() != ')':
492 raise BadExpression(ERR_MATCH
)
493 except BadExpression
:
494 raise BadExpression(ERR_MATCH
)
498 # Skip whitespace or tab
500 for Char
in self
._Expr
[self
._Idx
:]:
501 if Char
not in ' \t':
505 # Try to convert string to number
506 def __IsNumberToken(self
):
508 if self
._Token
.lower()[0:2] == '0x' and len(self
._Token
) > 2:
511 self
._Token
= int(self
._Token
, Radix
)
519 def __GetArray(self
):
522 self
.__GetNList
(True)
523 Token
+= self
._LiteralToken
524 if self
._Idx
>= self
._Len
or self
._Expr
[self
._Idx
] != '}':
525 raise BadExpression(ERR_ARRAY_TOKEN
% Token
)
528 # All whitespace and tabs in array are already stripped.
529 IsArray
= IsGuid
= False
530 if len(Token
.split(',')) == 11 and len(Token
.split(',{')) == 2 \
531 and len(Token
.split('},')) == 1:
532 HexLen
= [11, 6, 6, 5, 4, 4, 4, 4, 4, 4, 6]
533 HexList
= Token
.split(',')
534 if HexList
[3].startswith('{') and \
535 not [Index
for Index
, Hex
in enumerate(HexList
) if len(Hex
) > HexLen
[Index
]]:
537 if Token
.lstrip('{').rstrip('}').find('{') == -1:
538 if not [Hex
for Hex
in Token
.lstrip('{').rstrip('}').split(',') if len(Hex
) > 4]:
540 if not IsArray
and not IsGuid
:
541 raise BadExpression(ERR_ARRAY_TOKEN
% Token
)
543 self
._Token
= self
._LiteralToken
= Token
546 # Parse string, the format must be: "..."
547 def __GetString(self
):
553 # Replace escape \\\", \"
554 Expr
= self
._Expr
[self
._Idx
:].replace('\\\\', '//').replace('\\\"', '\\\'')
559 self
._Token
= self
._LiteralToken
= self
._Expr
[Idx
:self
._Idx
]
560 if not self
._Token
.endswith('"'):
561 raise BadExpression(ERR_STRING_TOKEN
% self
._Token
)
562 self
._Token
= self
._Token
[1:-1]
565 # Get token that is comprised by alphanumeric, underscore or dot(used by PCD)
566 # @param IsAlphaOp: Indicate if parsing general token or script operator(EQ, NE...)
567 def __GetIdToken(self
, IsAlphaOp
= False):
569 for Ch
in self
._Expr
[self
._Idx
:]:
570 if not self
.__IsIdChar
(Ch
):
575 self
._Token
= self
._LiteralToken
= IdToken
577 self
.__ResolveToken
()
580 # Try to resolve token
581 def __ResolveToken(self
):
583 raise BadExpression(ERR_EMPTY_TOKEN
)
586 if self
.PcdPattern
.match(self
._Token
):
587 if self
._Token
not in self
._Symb
:
588 Ex
= BadExpression(ERR_PCD_RESOLVE
% self
._Token
)
591 self
._Token
= RangeExpression(self
._Symb
[self
._Token
], self
._Symb
)(True, self
._Depth
+ 1)
592 if type(self
._Token
) != type(''):
593 self
._LiteralToken
= hex(self
._Token
)
596 if self
._Token
.startswith('"'):
597 self
._Token
= self
._Token
[1:-1]
598 elif self
._Token
in ["FALSE", "false", "False"]:
600 elif self
._Token
in ["TRUE", "true", "True"]:
603 self
.__IsNumberToken
()
605 def __GetNList(self
, InArray
= False):
606 self
._GetSingleToken
()
607 if not self
.__IsHexLiteral
():
609 raise BadExpression(ERR_ARRAY_ELE
% self
._Token
)
613 Expr
= self
._Expr
[self
._Idx
:]
614 if not Expr
.startswith(','):
617 NList
= self
._LiteralToken
618 while Expr
.startswith(','):
622 self
._GetSingleToken
()
623 if not self
.__IsHexLiteral
():
624 raise BadExpression(ERR_ARRAY_ELE
% self
._Token
)
625 NList
+= self
._LiteralToken
627 Expr
= self
._Expr
[self
._Idx
:]
628 self
._Token
= self
._LiteralToken
= NList
631 def __IsHexLiteral(self
):
632 if self
._LiteralToken
.startswith('{') and \
633 self
._LiteralToken
.endswith('}'):
636 if self
.HexPattern
.match(self
._LiteralToken
):
637 Token
= self
._LiteralToken
[2:]
638 Token
= Token
.lstrip('0')
640 self
._LiteralToken
= '0x0'
642 self
._LiteralToken
= '0x' + Token
.lower()
647 return self
.__GetNList
()
651 return Ch
in '._/:' or Ch
.isalnum()
654 def _GetSingleToken(self
):
656 Expr
= self
._Expr
[self
._Idx
:]
657 if Expr
.startswith('L"'):
660 UStr
= self
.__GetString
()
661 self
._Token
= 'L"' + UStr
+ '"'
667 Match
= self
.RegGuidPattern
.match(Expr
)
668 if Match
and not Expr
[Match
.end():Match
.end() + 1].isalnum() \
669 and Expr
[Match
.end():Match
.end() + 1] != '_':
670 self
._Idx
+= Match
.end()
671 self
._Token
= Expr
[0:Match
.end()]
673 elif self
.__IsIdChar
(Ch
):
674 return self
.__GetIdToken
()
675 elif Ch
== '(' or Ch
== ')':
680 raise BadExpression(ERR_VALID_TOKEN
% Expr
)
683 def _GetOperator(self
):
685 LegalOpLst
= ['&&', '||', '!=', '==', '>=', '<='] + self
.NonLetterOpLst
688 Expr
= self
._Expr
[self
._Idx
:]
690 # Reach end of expression
694 # Script operator: LT, GT, LE, GE, EQ, NE, and, or, xor, not
695 if Expr
[0].isalpha():
696 return self
.__GetIdToken
(True)
698 # Start to get regular operator: +, -, <, > ...
699 if Expr
[0] not in self
.NonLetterOpLst
:
704 if Ch
in self
.NonLetterOpLst
:
705 if '!' == Ch
and OpToken
:
712 if OpToken
not in LegalOpLst
:
713 raise BadExpression(ERR_OPERATOR_UNSUPPORT
% OpToken
)
714 self
._Token
= OpToken
717 # Check if current token matches the operators given from OpList
718 def _IsOperator(self
, OpList
):
721 if self
._Token
in OpList
:
722 if self
._Token
in self
.LogicalOperators
:
723 self
._Token
= self
.LogicalOperators
[self
._Token
]