]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Common/RangeExpression.py
BaseTools: use set instead of list
[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,BaseExpression
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(BaseExpression):
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 super(RangeExpression, self).__init__(self, Expression, PcdDataType, SymbolTable)
351 self._NoProcess = False
352 if type(Expression) != type(''):
353 self._Expr = Expression
354 self._NoProcess = True
355 return
356
357 self._Expr = Expression.strip()
358
359 if not self._Expr.strip():
360 raise BadExpression(ERR_EMPTY_EXPR)
361
362 #
363 # The symbol table including PCD and macro mapping
364 #
365 self._Symb = SymbolTable
366 self._Symb.update(self.LogicalOperators)
367 self._Idx = 0
368 self._Len = len(self._Expr)
369 self._Token = ''
370 self._WarnExcept = None
371
372
373 # Literal token without any conversion
374 self._LiteralToken = ''
375
376 # store the operand object
377 self.operanddict = {}
378 # The Pcd max value depends on PcdDataType
379 self.PcdDataType = PcdDataType
380
381 # Public entry for this class
382 # @param RealValue: False: only evaluate if the expression is true or false, used for conditional expression
383 # True : return the evaluated str(value), used for PCD value
384 #
385 # @return: True or False if RealValue is False
386 # Evaluated value of string format if RealValue is True
387 #
388 def __call__(self, RealValue = False, Depth = 0):
389 if self._NoProcess:
390 return self._Expr
391
392 self._Depth = Depth
393
394 self._Expr = self._Expr.strip()
395
396 self.preProcessRangeExpr(self._Expr)
397
398 # check if the expression does not need to evaluate
399 if RealValue and Depth == 0:
400 self._Token = self._Expr
401 if gGuidPatternEnd.match(self._Expr):
402 return [self.operanddict[self._Expr] ]
403
404 self._Idx = 0
405 self._Token = ''
406
407 Val = self._OrExpr()
408 RealVal = Val
409
410 RangeIdList = RealVal.split("or")
411 RangeList = []
412 for rangeid in RangeIdList:
413 RangeList.append(self.operanddict[rangeid.strip()])
414
415 return RangeList
416
417 # Template function to parse binary operators which have same precedence
418 # Expr [Operator Expr]*
419 def _ExprFuncTemplate(self, EvalFunc, OpSet):
420 Val = EvalFunc()
421 while self._IsOperator(OpSet):
422 Op = self._Token
423 try:
424 Val = self.Eval(Op, Val, EvalFunc())
425 except WrnExpression, Warn:
426 self._WarnExcept = Warn
427 Val = Warn.result
428 return Val
429
430 # A [|| B]*
431 def _OrExpr(self):
432 return self._ExprFuncTemplate(self._AndExpr, {"OR", "or"})
433
434 # A [&& B]*
435 def _AndExpr(self):
436 return self._ExprFuncTemplate(self._NeExpr, {"AND", "and"})
437
438 def _NeExpr(self):
439 Val = self._RelExpr()
440 while self._IsOperator({"!=", "NOT", "not"}):
441 Op = self._Token
442 if Op in ["!", "NOT", "not"]:
443 if not self._IsOperator({"IN", "in"}):
444 raise BadExpression(ERR_REL_NOT_IN)
445 Op += ' ' + self._Token
446 try:
447 Val = self.Eval(Op, Val, self._RelExpr())
448 except WrnExpression, Warn:
449 self._WarnExcept = Warn
450 Val = Warn.result
451 return Val
452
453 # [!]*A
454 def _RelExpr(self):
455 if self._IsOperator({"NOT" , "LE", "GE", "LT", "GT", "EQ", "XOR"}):
456 Token = self._Token
457 Val = self._NeExpr()
458 try:
459 return self.Eval(Token, Val)
460 except WrnExpression, Warn:
461 self._WarnExcept = Warn
462 return Warn.result
463 return self._IdenExpr()
464
465 # Parse identifier or encapsulated expression
466 def _IdenExpr(self):
467 Tk = self._GetToken()
468 if Tk == '(':
469 Val = self._OrExpr()
470 try:
471 # _GetToken may also raise BadExpression
472 if self._GetToken() != ')':
473 raise BadExpression(ERR_MATCH)
474 except BadExpression:
475 raise BadExpression(ERR_MATCH)
476 return Val
477 return Tk
478
479 # Skip whitespace or tab
480 def __SkipWS(self):
481 for Char in self._Expr[self._Idx:]:
482 if Char not in ' \t':
483 break
484 self._Idx += 1
485
486 # Try to convert string to number
487 def __IsNumberToken(self):
488 Radix = 10
489 if self._Token.lower()[0:2] == '0x' and len(self._Token) > 2:
490 Radix = 16
491 try:
492 self._Token = int(self._Token, Radix)
493 return True
494 except ValueError:
495 return False
496 except TypeError:
497 return False
498
499 # Parse array: {...}
500 def __GetArray(self):
501 Token = '{'
502 self._Idx += 1
503 self.__GetNList(True)
504 Token += self._LiteralToken
505 if self._Idx >= self._Len or self._Expr[self._Idx] != '}':
506 raise BadExpression(ERR_ARRAY_TOKEN % Token)
507 Token += '}'
508
509 # All whitespace and tabs in array are already stripped.
510 IsArray = IsGuid = False
511 if len(Token.split(',')) == 11 and len(Token.split(',{')) == 2 \
512 and len(Token.split('},')) == 1:
513 HexLen = [11, 6, 6, 5, 4, 4, 4, 4, 4, 4, 6]
514 HexList = Token.split(',')
515 if HexList[3].startswith('{') and \
516 not [Index for Index, Hex in enumerate(HexList) if len(Hex) > HexLen[Index]]:
517 IsGuid = True
518 if Token.lstrip('{').rstrip('}').find('{') == -1:
519 if not [Hex for Hex in Token.lstrip('{').rstrip('}').split(',') if len(Hex) > 4]:
520 IsArray = True
521 if not IsArray and not IsGuid:
522 raise BadExpression(ERR_ARRAY_TOKEN % Token)
523 self._Idx += 1
524 self._Token = self._LiteralToken = Token
525 return self._Token
526
527 # Parse string, the format must be: "..."
528 def __GetString(self):
529 Idx = self._Idx
530
531 # Skip left quote
532 self._Idx += 1
533
534 # Replace escape \\\", \"
535 Expr = self._Expr[self._Idx:].replace('\\\\', '//').replace('\\\"', '\\\'')
536 for Ch in Expr:
537 self._Idx += 1
538 if Ch == '"':
539 break
540 self._Token = self._LiteralToken = self._Expr[Idx:self._Idx]
541 if not self._Token.endswith('"'):
542 raise BadExpression(ERR_STRING_TOKEN % self._Token)
543 self._Token = self._Token[1:-1]
544 return self._Token
545
546 # Get token that is comprised by alphanumeric, underscore or dot(used by PCD)
547 # @param IsAlphaOp: Indicate if parsing general token or script operator(EQ, NE...)
548 def __GetIdToken(self, IsAlphaOp = False):
549 IdToken = ''
550 for Ch in self._Expr[self._Idx:]:
551 if not self.__IsIdChar(Ch):
552 break
553 self._Idx += 1
554 IdToken += Ch
555
556 self._Token = self._LiteralToken = IdToken
557 if not IsAlphaOp:
558 self.__ResolveToken()
559 return self._Token
560
561 # Try to resolve token
562 def __ResolveToken(self):
563 if not self._Token:
564 raise BadExpression(ERR_EMPTY_TOKEN)
565
566 # PCD token
567 if PcdPattern.match(self._Token):
568 if self._Token not in self._Symb:
569 Ex = BadExpression(ERR_PCD_RESOLVE % self._Token)
570 Ex.Pcd = self._Token
571 raise Ex
572 self._Token = RangeExpression(self._Symb[self._Token], self._Symb)(True, self._Depth + 1)
573 if type(self._Token) != type(''):
574 self._LiteralToken = hex(self._Token)
575 return
576
577 if self._Token.startswith('"'):
578 self._Token = self._Token[1:-1]
579 elif self._Token in ["FALSE", "false", "False"]:
580 self._Token = False
581 elif self._Token in ["TRUE", "true", "True"]:
582 self._Token = True
583 else:
584 self.__IsNumberToken()
585
586 def __GetNList(self, InArray = False):
587 self._GetSingleToken()
588 if not self.__IsHexLiteral():
589 if InArray:
590 raise BadExpression(ERR_ARRAY_ELE % self._Token)
591 return self._Token
592
593 self.__SkipWS()
594 Expr = self._Expr[self._Idx:]
595 if not Expr.startswith(','):
596 return self._Token
597
598 NList = self._LiteralToken
599 while Expr.startswith(','):
600 NList += ','
601 self._Idx += 1
602 self.__SkipWS()
603 self._GetSingleToken()
604 if not self.__IsHexLiteral():
605 raise BadExpression(ERR_ARRAY_ELE % self._Token)
606 NList += self._LiteralToken
607 self.__SkipWS()
608 Expr = self._Expr[self._Idx:]
609 self._Token = self._LiteralToken = NList
610 return self._Token
611
612 def __IsHexLiteral(self):
613 if self._LiteralToken.startswith('{') and \
614 self._LiteralToken.endswith('}'):
615 return True
616
617 if gHexPattern.match(self._LiteralToken):
618 Token = self._LiteralToken[2:]
619 Token = Token.lstrip('0')
620 if not Token:
621 self._LiteralToken = '0x0'
622 else:
623 self._LiteralToken = '0x' + Token.lower()
624 return True
625 return False
626
627 def _GetToken(self):
628 return self.__GetNList()
629
630 @staticmethod
631 def __IsIdChar(Ch):
632 return Ch in '._/:' or Ch.isalnum()
633
634 # Parse operand
635 def _GetSingleToken(self):
636 self.__SkipWS()
637 Expr = self._Expr[self._Idx:]
638 if Expr.startswith('L"'):
639 # Skip L
640 self._Idx += 1
641 UStr = self.__GetString()
642 self._Token = 'L"' + UStr + '"'
643 return self._Token
644
645 self._Token = ''
646 if Expr:
647 Ch = Expr[0]
648 Match = gGuidPattern.match(Expr)
649 if Match and not Expr[Match.end():Match.end() + 1].isalnum() \
650 and Expr[Match.end():Match.end() + 1] != '_':
651 self._Idx += Match.end()
652 self._Token = Expr[0:Match.end()]
653 return self._Token
654 elif self.__IsIdChar(Ch):
655 return self.__GetIdToken()
656 elif Ch == '(' or Ch == ')':
657 self._Idx += 1
658 self._Token = Ch
659 return self._Token
660
661 raise BadExpression(ERR_VALID_TOKEN % Expr)
662
663 # Parse operator
664 def _GetOperator(self):
665 self.__SkipWS()
666 LegalOpLst = ['&&', '||', '!=', '==', '>=', '<='] + self.NonLetterOpLst
667
668 self._Token = ''
669 Expr = self._Expr[self._Idx:]
670
671 # Reach end of expression
672 if not Expr:
673 return ''
674
675 # Script operator: LT, GT, LE, GE, EQ, NE, and, or, xor, not
676 if Expr[0].isalpha():
677 return self.__GetIdToken(True)
678
679 # Start to get regular operator: +, -, <, > ...
680 if Expr[0] not in self.NonLetterOpLst:
681 return ''
682
683 OpToken = ''
684 for Ch in Expr:
685 if Ch in self.NonLetterOpLst:
686 if '!' == Ch and OpToken:
687 break
688 self._Idx += 1
689 OpToken += Ch
690 else:
691 break
692
693 if OpToken not in LegalOpLst:
694 raise BadExpression(ERR_OPERATOR_UNSUPPORT % OpToken)
695 self._Token = OpToken
696 return OpToken