]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Common/RangeExpression.py
BaseTools: merge towards minimum PCD MAX <something> methods
[mirror_edk2.git] / BaseTools / Source / Python / Common / RangeExpression.py
1 # # @file
2 # This file is used to parse and evaluate range expression in Pcd declaration.
3 #
4 # Copyright (c) 2015 - 2018, 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
9 #
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.
12
13 # # Import Modules
14 #
15 from Common.GlobalData import *
16 from CommonDataClass.Exceptions import BadExpression
17 from CommonDataClass.Exceptions import WrnExpression
18 import uuid
19 from Common.Expression import PcdPattern
20 from Common.DataType import *
21
22 ERR_STRING_EXPR = 'This operator cannot be used in string expression: [%s].'
23 ERR_SNYTAX = 'Syntax error, the rest of expression cannot be evaluated: [%s].'
24 ERR_MATCH = 'No matching right parenthesis.'
25 ERR_STRING_TOKEN = 'Bad string token: [%s].'
26 ERR_MACRO_TOKEN = 'Bad macro token: [%s].'
27 ERR_EMPTY_TOKEN = 'Empty token is not allowed.'
28 ERR_PCD_RESOLVE = 'PCD token cannot be resolved: [%s].'
29 ERR_VALID_TOKEN = 'No more valid token found from rest of string: [%s].'
30 ERR_EXPR_TYPE = 'Different types found in expression.'
31 ERR_OPERATOR_UNSUPPORT = 'Unsupported operator: [%s]'
32 ERR_REL_NOT_IN = 'Expect "IN" after "not" operator.'
33 WRN_BOOL_EXPR = 'Operand of boolean type cannot be used in arithmetic expression.'
34 WRN_EQCMP_STR_OTHERS = '== Comparison between Operand of string type and Boolean/Number Type always return False.'
35 WRN_NECMP_STR_OTHERS = '!= Comparison between Operand of string type and Boolean/Number Type always return True.'
36 ERR_RELCMP_STR_OTHERS = 'Operator taking Operand of string type and Boolean/Number Type is not allowed: [%s].'
37 ERR_STRING_CMP = 'Unicode string and general string cannot be compared: [%s %s %s]'
38 ERR_ARRAY_TOKEN = 'Bad C array or C format GUID token: [%s].'
39 ERR_ARRAY_ELE = 'This must be HEX value for NList or Array: [%s].'
40 ERR_EMPTY_EXPR = 'Empty expression is not allowed.'
41 ERR_IN_OPERAND = 'Macro after IN operator can only be: $(FAMILY), $(ARCH), $(TOOL_CHAIN_TAG) and $(TARGET).'
42
43 class RangeObject(object):
44 def __init__(self, start, end, empty = False):
45
46 if int(start) < int(end):
47 self.start = int(start)
48 self.end = int(end)
49 else:
50 self.start = int(end)
51 self.end = int(start)
52 self.empty = empty
53
54 class RangeContainer(object):
55 def __init__(self):
56 self.rangelist = []
57
58 def push(self, RangeObject):
59 self.rangelist.append(RangeObject)
60 self.rangelist = sorted(self.rangelist, key = lambda rangeobj : rangeobj.start)
61 self.merge()
62
63 def pop(self):
64 for item in self.rangelist:
65 yield item
66
67 def __clean__(self):
68 newrangelist = []
69 for rangeobj in self.rangelist:
70 if rangeobj.empty == True:
71 continue
72 else:
73 newrangelist.append(rangeobj)
74 self.rangelist = newrangelist
75 def merge(self):
76 self.__clean__()
77 for i in range(0, len(self.rangelist) - 1):
78 if self.rangelist[i + 1].start > self.rangelist[i].end:
79 continue
80 else:
81 self.rangelist[i + 1].start = self.rangelist[i].start
82 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
83 self.rangelist[i].empty = True
84
85 self.__clean__()
86
87 def dump(self):
88 print "----------------------"
89 rangelist = ""
90 for object in self.rangelist:
91 rangelist = rangelist + "[%d , %d]" % (object.start, object.end)
92 print rangelist
93
94
95 class XOROperatorObject(object):
96 def __init__(self):
97 pass
98 def Calculate(self, Operand, DataType, SymbolTable):
99 if type(Operand) == type('') and not Operand.isalnum():
100 Expr = "XOR ..."
101 raise BadExpression(ERR_SNYTAX % Expr)
102 rangeId = str(uuid.uuid1())
103 rangeContainer = RangeContainer()
104 rangeContainer.push(RangeObject(0, int(Operand) - 1))
105 rangeContainer.push(RangeObject(int(Operand) + 1, MAX_VAL_TYPE[DataType]))
106 SymbolTable[rangeId] = rangeContainer
107 return rangeId
108
109 class LEOperatorObject(object):
110 def __init__(self):
111 pass
112 def Calculate(self, Operand, DataType, SymbolTable):
113 if type(Operand) == type('') and not Operand.isalnum():
114 Expr = "LE ..."
115 raise BadExpression(ERR_SNYTAX % Expr)
116 rangeId1 = str(uuid.uuid1())
117 rangeContainer = RangeContainer()
118 rangeContainer.push(RangeObject(0, int(Operand)))
119 SymbolTable[rangeId1] = rangeContainer
120 return rangeId1
121 class LTOperatorObject(object):
122 def __init__(self):
123 pass
124 def Calculate(self, Operand, DataType, SymbolTable):
125 if type(Operand) == type('') and not Operand.isalnum():
126 Expr = "LT ..."
127 raise BadExpression(ERR_SNYTAX % Expr)
128 rangeId1 = str(uuid.uuid1())
129 rangeContainer = RangeContainer()
130 rangeContainer.push(RangeObject(0, int(Operand) - 1))
131 SymbolTable[rangeId1] = rangeContainer
132 return rangeId1
133
134 class GEOperatorObject(object):
135 def __init__(self):
136 pass
137 def Calculate(self, Operand, DataType, SymbolTable):
138 if type(Operand) == type('') and not Operand.isalnum():
139 Expr = "GE ..."
140 raise BadExpression(ERR_SNYTAX % Expr)
141 rangeId1 = str(uuid.uuid1())
142 rangeContainer = RangeContainer()
143 rangeContainer.push(RangeObject(int(Operand), MAX_VAL_TYPE[DataType]))
144 SymbolTable[rangeId1] = rangeContainer
145 return rangeId1
146
147 class GTOperatorObject(object):
148 def __init__(self):
149 pass
150 def Calculate(self, Operand, DataType, SymbolTable):
151 if type(Operand) == type('') and not Operand.isalnum():
152 Expr = "GT ..."
153 raise BadExpression(ERR_SNYTAX % Expr)
154 rangeId1 = str(uuid.uuid1())
155 rangeContainer = RangeContainer()
156 rangeContainer.push(RangeObject(int(Operand) + 1, MAX_VAL_TYPE[DataType]))
157 SymbolTable[rangeId1] = rangeContainer
158 return rangeId1
159
160 class EQOperatorObject(object):
161 def __init__(self):
162 pass
163 def Calculate(self, Operand, DataType, SymbolTable):
164 if type(Operand) == type('') and not Operand.isalnum():
165 Expr = "EQ ..."
166 raise BadExpression(ERR_SNYTAX % Expr)
167 rangeId1 = str(uuid.uuid1())
168 rangeContainer = RangeContainer()
169 rangeContainer.push(RangeObject(int(Operand) , int(Operand)))
170 SymbolTable[rangeId1] = rangeContainer
171 return rangeId1
172
173 def GetOperatorObject(Operator):
174 if Operator == '>':
175 return GTOperatorObject()
176 elif Operator == '>=':
177 return GEOperatorObject()
178 elif Operator == '<':
179 return LTOperatorObject()
180 elif Operator == '<=':
181 return LEOperatorObject()
182 elif Operator == '==':
183 return EQOperatorObject()
184 elif Operator == '^':
185 return XOROperatorObject()
186 else:
187 raise BadExpression("Bad Operator")
188
189 class RangeExpression(object):
190 # Logical operator mapping
191 LogicalOperators = {
192 '&&' : 'and', '||' : 'or',
193 '!' : 'not', 'AND': 'and',
194 'OR' : 'or' , 'NOT': 'not',
195 'XOR': '^' , 'xor': '^',
196 'EQ' : '==' , 'NE' : '!=',
197 'GT' : '>' , 'LT' : '<',
198 'GE' : '>=' , 'LE' : '<=',
199 'IN' : 'in'
200 }
201
202 NonLetterOpLst = ['+', '-', '&', '|', '^', '!', '=', '>', '<']
203
204 RangePattern = re.compile(r'[0-9]+ - [0-9]+')
205
206 def preProcessRangeExpr(self, expr):
207 # convert hex to int
208 # convert interval to object index. ex. 1 - 10 to a GUID
209 expr = expr.strip()
210 NumberDict = {}
211 for HexNumber in gHexPattern.findall(expr):
212 Number = str(int(HexNumber, 16))
213 NumberDict[HexNumber] = Number
214 for HexNum in NumberDict:
215 expr = expr.replace(HexNum, NumberDict[HexNum])
216
217 rangedict = {}
218 for validrange in self.RangePattern.findall(expr):
219 start, end = validrange.split(" - ")
220 start = start.strip()
221 end = end.strip()
222 rangeid = str(uuid.uuid1())
223 rangeContainer = RangeContainer()
224 rangeContainer.push(RangeObject(start, end))
225 self.operanddict[str(rangeid)] = rangeContainer
226 rangedict[validrange] = str(rangeid)
227
228 for validrange in rangedict:
229 expr = expr.replace(validrange, rangedict[validrange])
230
231 self._Expr = expr
232 return expr
233
234
235 def EvalRange(self, Operator, Oprand):
236
237 operatorobj = GetOperatorObject(Operator)
238 return operatorobj.Calculate(Oprand, self.PcdDataType, self.operanddict)
239
240 def Rangeintersection(self, Oprand1, Oprand2):
241 rangeContainer1 = self.operanddict[Oprand1]
242 rangeContainer2 = self.operanddict[Oprand2]
243 rangeContainer = RangeContainer()
244 for range1 in rangeContainer1.pop():
245 for range2 in rangeContainer2.pop():
246 start1 = range1.start
247 end1 = range1.end
248 start2 = range2.start
249 end2 = range2.end
250 if start1 >= start2:
251 start1, start2 = start2, start1
252 end1, end2 = end2, end1
253 if range1.empty:
254 rangeid = str(uuid.uuid1())
255 rangeContainer.push(RangeObject(0, 0, True))
256 if end1 < start2:
257 rangeid = str(uuid.uuid1())
258 rangeContainer.push(RangeObject(0, 0, True))
259 elif end1 == start2:
260 rangeid = str(uuid.uuid1())
261 rangeContainer.push(RangeObject(end1, end1))
262 elif end1 <= end2 and end1 > start2:
263 rangeid = str(uuid.uuid1())
264 rangeContainer.push(RangeObject(start2, end1))
265 elif end1 >= end2:
266 rangeid = str(uuid.uuid1())
267 rangeContainer.push(RangeObject(start2, end2))
268
269 self.operanddict[rangeid] = rangeContainer
270 # rangeContainer.dump()
271 return rangeid
272
273 def Rangecollections(self, Oprand1, Oprand2):
274
275 rangeContainer1 = self.operanddict[Oprand1]
276 rangeContainer2 = self.operanddict[Oprand2]
277 rangeContainer = RangeContainer()
278
279 for rangeobj in rangeContainer2.pop():
280 rangeContainer.push(rangeobj)
281 for rangeobj in rangeContainer1.pop():
282 rangeContainer.push(rangeobj)
283
284 rangeid = str(uuid.uuid1())
285 self.operanddict[rangeid] = rangeContainer
286
287 # rangeContainer.dump()
288 return rangeid
289
290
291 def NegtiveRange(self, Oprand1):
292 rangeContainer1 = self.operanddict[Oprand1]
293
294
295 rangeids = []
296
297 for rangeobj in rangeContainer1.pop():
298 rangeContainer = RangeContainer()
299 rangeid = str(uuid.uuid1())
300 if rangeobj.empty:
301 rangeContainer.push(RangeObject(0, MAX_VAL_TYPE[self.PcdDataType]))
302 else:
303 if rangeobj.start > 0:
304 rangeContainer.push(RangeObject(0, rangeobj.start - 1))
305 if rangeobj.end < MAX_VAL_TYPE[self.PcdDataType]:
306 rangeContainer.push(RangeObject(rangeobj.end + 1, MAX_VAL_TYPE[self.PcdDataType]))
307 self.operanddict[rangeid] = rangeContainer
308 rangeids.append(rangeid)
309
310 if len(rangeids) == 0:
311 rangeContainer = RangeContainer()
312 rangeContainer.push(RangeObject(0, MAX_VAL_TYPE[self.PcdDataType]))
313 rangeid = str(uuid.uuid1())
314 self.operanddict[rangeid] = rangeContainer
315 return rangeid
316
317 if len(rangeids) == 1:
318 return rangeids[0]
319
320 re = self.Rangeintersection(rangeids[0], rangeids[1])
321 for i in range(2, len(rangeids)):
322 re = self.Rangeintersection(re, rangeids[i])
323
324 rangeid2 = str(uuid.uuid1())
325 self.operanddict[rangeid2] = self.operanddict[re]
326 return rangeid2
327
328 def Eval(self, Operator, Oprand1, Oprand2 = None):
329
330 if Operator in ["!", "NOT", "not"]:
331 if not gGuidPattern.match(Oprand1.strip()):
332 raise BadExpression(ERR_STRING_EXPR % Operator)
333 return self.NegtiveRange(Oprand1)
334 else:
335 if Operator in ["==", ">=", "<=", ">", "<", '^']:
336 return self.EvalRange(Operator, Oprand1)
337 elif Operator == 'and' :
338 if not gGuidPatternEnd.match(Oprand1.strip()) or not gGuidPatternEnd.match(Oprand2.strip()):
339 raise BadExpression(ERR_STRING_EXPR % Operator)
340 return self.Rangeintersection(Oprand1, Oprand2)
341 elif Operator == 'or':
342 if not gGuidPatternEnd.match(Oprand1.strip()) or not gGuidPatternEnd.match(Oprand2.strip()):
343 raise BadExpression(ERR_STRING_EXPR % Operator)
344 return self.Rangecollections(Oprand1, Oprand2)
345 else:
346 raise BadExpression(ERR_STRING_EXPR % Operator)
347
348
349 def __init__(self, Expression, PcdDataType, SymbolTable = {}):
350 self._NoProcess = False
351 if type(Expression) != type(''):
352 self._Expr = Expression
353 self._NoProcess = True
354 return
355
356 self._Expr = Expression.strip()
357
358 if not self._Expr.strip():
359 raise BadExpression(ERR_EMPTY_EXPR)
360
361 #
362 # The symbol table including PCD and macro mapping
363 #
364 self._Symb = SymbolTable
365 self._Symb.update(self.LogicalOperators)
366 self._Idx = 0
367 self._Len = len(self._Expr)
368 self._Token = ''
369 self._WarnExcept = None
370
371
372 # Literal token without any conversion
373 self._LiteralToken = ''
374
375 # store the operand object
376 self.operanddict = {}
377 # The Pcd max value depends on PcdDataType
378 self.PcdDataType = PcdDataType
379
380 # Public entry for this class
381 # @param RealValue: False: only evaluate if the expression is true or false, used for conditional expression
382 # True : return the evaluated str(value), used for PCD value
383 #
384 # @return: True or False if RealValue is False
385 # Evaluated value of string format if RealValue is True
386 #
387 def __call__(self, RealValue = False, Depth = 0):
388 if self._NoProcess:
389 return self._Expr
390
391 self._Depth = Depth
392
393 self._Expr = self._Expr.strip()
394
395 self.preProcessRangeExpr(self._Expr)
396
397 # check if the expression does not need to evaluate
398 if RealValue and Depth == 0:
399 self._Token = self._Expr
400 if gGuidPatternEnd.match(self._Expr):
401 return [self.operanddict[self._Expr] ]
402
403 self._Idx = 0
404 self._Token = ''
405
406 Val = self._OrExpr()
407 RealVal = Val
408
409 RangeIdList = RealVal.split("or")
410 RangeList = []
411 for rangeid in RangeIdList:
412 RangeList.append(self.operanddict[rangeid.strip()])
413
414 return RangeList
415
416 # Template function to parse binary operators which have same precedence
417 # Expr [Operator Expr]*
418 def _ExprFuncTemplate(self, EvalFunc, OpLst):
419 Val = EvalFunc()
420 while self._IsOperator(OpLst):
421 Op = self._Token
422 try:
423 Val = self.Eval(Op, Val, EvalFunc())
424 except WrnExpression, Warn:
425 self._WarnExcept = Warn
426 Val = Warn.result
427 return Val
428
429 # A [|| B]*
430 def _OrExpr(self):
431 return self._ExprFuncTemplate(self._AndExpr, ["OR", "or"])
432
433 # A [&& B]*
434 def _AndExpr(self):
435 return self._ExprFuncTemplate(self._NeExpr, ["AND", "and"])
436
437 def _NeExpr(self):
438 Val = self._RelExpr()
439 while self._IsOperator([ "!=", "NOT", "not"]):
440 Op = self._Token
441 if Op in ["!", "NOT", "not"]:
442 if not self._IsOperator(["IN", "in"]):
443 raise BadExpression(ERR_REL_NOT_IN)
444 Op += ' ' + self._Token
445 try:
446 Val = self.Eval(Op, Val, self._RelExpr())
447 except WrnExpression, Warn:
448 self._WarnExcept = Warn
449 Val = Warn.result
450 return Val
451
452 # [!]*A
453 def _RelExpr(self):
454 if self._IsOperator(["NOT" , "LE", "GE", "LT", "GT", "EQ", "XOR"]):
455 Token = self._Token
456 Val = self._NeExpr()
457 try:
458 return self.Eval(Token, Val)
459 except WrnExpression, Warn:
460 self._WarnExcept = Warn
461 return Warn.result
462 return self._IdenExpr()
463
464 # Parse identifier or encapsulated expression
465 def _IdenExpr(self):
466 Tk = self._GetToken()
467 if Tk == '(':
468 Val = self._OrExpr()
469 try:
470 # _GetToken may also raise BadExpression
471 if self._GetToken() != ')':
472 raise BadExpression(ERR_MATCH)
473 except BadExpression:
474 raise BadExpression(ERR_MATCH)
475 return Val
476 return Tk
477
478 # Skip whitespace or tab
479 def __SkipWS(self):
480 for Char in self._Expr[self._Idx:]:
481 if Char not in ' \t':
482 break
483 self._Idx += 1
484
485 # Try to convert string to number
486 def __IsNumberToken(self):
487 Radix = 10
488 if self._Token.lower()[0:2] == '0x' and len(self._Token) > 2:
489 Radix = 16
490 try:
491 self._Token = int(self._Token, Radix)
492 return True
493 except ValueError:
494 return False
495 except TypeError:
496 return False
497
498 # Parse array: {...}
499 def __GetArray(self):
500 Token = '{'
501 self._Idx += 1
502 self.__GetNList(True)
503 Token += self._LiteralToken
504 if self._Idx >= self._Len or self._Expr[self._Idx] != '}':
505 raise BadExpression(ERR_ARRAY_TOKEN % Token)
506 Token += '}'
507
508 # All whitespace and tabs in array are already stripped.
509 IsArray = IsGuid = False
510 if len(Token.split(',')) == 11 and len(Token.split(',{')) == 2 \
511 and len(Token.split('},')) == 1:
512 HexLen = [11, 6, 6, 5, 4, 4, 4, 4, 4, 4, 6]
513 HexList = Token.split(',')
514 if HexList[3].startswith('{') and \
515 not [Index for Index, Hex in enumerate(HexList) if len(Hex) > HexLen[Index]]:
516 IsGuid = True
517 if Token.lstrip('{').rstrip('}').find('{') == -1:
518 if not [Hex for Hex in Token.lstrip('{').rstrip('}').split(',') if len(Hex) > 4]:
519 IsArray = True
520 if not IsArray and not IsGuid:
521 raise BadExpression(ERR_ARRAY_TOKEN % Token)
522 self._Idx += 1
523 self._Token = self._LiteralToken = Token
524 return self._Token
525
526 # Parse string, the format must be: "..."
527 def __GetString(self):
528 Idx = self._Idx
529
530 # Skip left quote
531 self._Idx += 1
532
533 # Replace escape \\\", \"
534 Expr = self._Expr[self._Idx:].replace('\\\\', '//').replace('\\\"', '\\\'')
535 for Ch in Expr:
536 self._Idx += 1
537 if Ch == '"':
538 break
539 self._Token = self._LiteralToken = self._Expr[Idx:self._Idx]
540 if not self._Token.endswith('"'):
541 raise BadExpression(ERR_STRING_TOKEN % self._Token)
542 self._Token = self._Token[1:-1]
543 return self._Token
544
545 # Get token that is comprised by alphanumeric, underscore or dot(used by PCD)
546 # @param IsAlphaOp: Indicate if parsing general token or script operator(EQ, NE...)
547 def __GetIdToken(self, IsAlphaOp = False):
548 IdToken = ''
549 for Ch in self._Expr[self._Idx:]:
550 if not self.__IsIdChar(Ch):
551 break
552 self._Idx += 1
553 IdToken += Ch
554
555 self._Token = self._LiteralToken = IdToken
556 if not IsAlphaOp:
557 self.__ResolveToken()
558 return self._Token
559
560 # Try to resolve token
561 def __ResolveToken(self):
562 if not self._Token:
563 raise BadExpression(ERR_EMPTY_TOKEN)
564
565 # PCD token
566 if PcdPattern.match(self._Token):
567 if self._Token not in self._Symb:
568 Ex = BadExpression(ERR_PCD_RESOLVE % self._Token)
569 Ex.Pcd = self._Token
570 raise Ex
571 self._Token = RangeExpression(self._Symb[self._Token], self._Symb)(True, self._Depth + 1)
572 if type(self._Token) != type(''):
573 self._LiteralToken = hex(self._Token)
574 return
575
576 if self._Token.startswith('"'):
577 self._Token = self._Token[1:-1]
578 elif self._Token in ["FALSE", "false", "False"]:
579 self._Token = False
580 elif self._Token in ["TRUE", "true", "True"]:
581 self._Token = True
582 else:
583 self.__IsNumberToken()
584
585 def __GetNList(self, InArray = False):
586 self._GetSingleToken()
587 if not self.__IsHexLiteral():
588 if InArray:
589 raise BadExpression(ERR_ARRAY_ELE % self._Token)
590 return self._Token
591
592 self.__SkipWS()
593 Expr = self._Expr[self._Idx:]
594 if not Expr.startswith(','):
595 return self._Token
596
597 NList = self._LiteralToken
598 while Expr.startswith(','):
599 NList += ','
600 self._Idx += 1
601 self.__SkipWS()
602 self._GetSingleToken()
603 if not self.__IsHexLiteral():
604 raise BadExpression(ERR_ARRAY_ELE % self._Token)
605 NList += self._LiteralToken
606 self.__SkipWS()
607 Expr = self._Expr[self._Idx:]
608 self._Token = self._LiteralToken = NList
609 return self._Token
610
611 def __IsHexLiteral(self):
612 if self._LiteralToken.startswith('{') and \
613 self._LiteralToken.endswith('}'):
614 return True
615
616 if gHexPattern.match(self._LiteralToken):
617 Token = self._LiteralToken[2:]
618 Token = Token.lstrip('0')
619 if not Token:
620 self._LiteralToken = '0x0'
621 else:
622 self._LiteralToken = '0x' + Token.lower()
623 return True
624 return False
625
626 def _GetToken(self):
627 return self.__GetNList()
628
629 @staticmethod
630 def __IsIdChar(Ch):
631 return Ch in '._/:' or Ch.isalnum()
632
633 # Parse operand
634 def _GetSingleToken(self):
635 self.__SkipWS()
636 Expr = self._Expr[self._Idx:]
637 if Expr.startswith('L"'):
638 # Skip L
639 self._Idx += 1
640 UStr = self.__GetString()
641 self._Token = 'L"' + UStr + '"'
642 return self._Token
643
644 self._Token = ''
645 if Expr:
646 Ch = Expr[0]
647 Match = gGuidPattern.match(Expr)
648 if Match and not Expr[Match.end():Match.end() + 1].isalnum() \
649 and Expr[Match.end():Match.end() + 1] != '_':
650 self._Idx += Match.end()
651 self._Token = Expr[0:Match.end()]
652 return self._Token
653 elif self.__IsIdChar(Ch):
654 return self.__GetIdToken()
655 elif Ch == '(' or Ch == ')':
656 self._Idx += 1
657 self._Token = Ch
658 return self._Token
659
660 raise BadExpression(ERR_VALID_TOKEN % Expr)
661
662 # Parse operator
663 def _GetOperator(self):
664 self.__SkipWS()
665 LegalOpLst = ['&&', '||', '!=', '==', '>=', '<='] + self.NonLetterOpLst
666
667 self._Token = ''
668 Expr = self._Expr[self._Idx:]
669
670 # Reach end of expression
671 if not Expr:
672 return ''
673
674 # Script operator: LT, GT, LE, GE, EQ, NE, and, or, xor, not
675 if Expr[0].isalpha():
676 return self.__GetIdToken(True)
677
678 # Start to get regular operator: +, -, <, > ...
679 if Expr[0] not in self.NonLetterOpLst:
680 return ''
681
682 OpToken = ''
683 for Ch in Expr:
684 if Ch in self.NonLetterOpLst:
685 if '!' == Ch and OpToken:
686 break
687 self._Idx += 1
688 OpToken += Ch
689 else:
690 break
691
692 if OpToken not in LegalOpLst:
693 raise BadExpression(ERR_OPERATOR_UNSUPPORT % OpToken)
694 self._Token = OpToken
695 return OpToken
696
697 # Check if current token matches the operators given from OpList
698 def _IsOperator(self, OpList):
699 Idx = self._Idx
700 self._GetOperator()
701 if self._Token in OpList:
702 if self._Token in self.LogicalOperators:
703 self._Token = self.LogicalOperators[self._Token]
704 return True
705 self._Idx = Idx
706 return False
707
708
709
710
711
712
713
714
715
716
717 # UTRangeList()