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