Home | History | Annotate | Download | only in match
      1 # Copyright (C) 2014 The Android Open Source Project
      2 #
      3 # Licensed under the Apache License, Version 2.0 (the "License");
      4 # you may not use this file except in compliance with the License.
      5 # You may obtain a copy of the License at
      6 #
      7 #   http://www.apache.org/licenses/LICENSE-2.0
      8 #
      9 # Unless required by applicable law or agreed to in writing, software
     10 # distributed under the License is distributed on an "AS IS" BASIS,
     11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 # See the License for the specific language governing permissions and
     13 # limitations under the License.
     14 
     15 from common.logger              import Logger
     16 from file_format.checker.struct import TestExpression, TestAssertion
     17 
     18 import re
     19 
     20 def headAndTail(list):
     21   return list[0], list[1:]
     22 
     23 def splitAtSeparators(expressions):
     24   """ Splits a list of TestExpressions at separators. """
     25   splitExpressions = []
     26   wordStart = 0
     27   for index, expression in enumerate(expressions):
     28     if expression.variant == TestExpression.Variant.Separator:
     29       splitExpressions.append(expressions[wordStart:index])
     30       wordStart = index + 1
     31   splitExpressions.append(expressions[wordStart:])
     32   return splitExpressions
     33 
     34 def getVariable(name, variables, pos):
     35   if name in variables:
     36     return variables[name]
     37   else:
     38     Logger.testFailed("Missing definition of variable \"{}\"".format(name), pos, variables)
     39 
     40 def setVariable(name, value, variables, pos):
     41   if name not in variables:
     42     return variables.copyWith(name, value)
     43   else:
     44     Logger.testFailed("Multiple definitions of variable \"{}\"".format(name), pos, variables)
     45 
     46 def matchWords(checkerWord, stringWord, variables, pos):
     47   """ Attempts to match a list of TestExpressions against a string.
     48       Returns updated variable dictionary if successful and None otherwise.
     49   """
     50   for expression in checkerWord:
     51     # If `expression` is a variable reference, replace it with the value.
     52     if expression.variant == TestExpression.Variant.VarRef:
     53       pattern = re.escape(getVariable(expression.name, variables, pos))
     54     else:
     55       pattern = expression.text
     56 
     57     # Match the expression's regex pattern against the remainder of the word.
     58     # Note: re.match will succeed only if matched from the beginning.
     59     match = re.match(pattern, stringWord)
     60     if not match:
     61       return None
     62 
     63     # If `expression` was a variable definition, set the variable's value.
     64     if expression.variant == TestExpression.Variant.VarDef:
     65       variables = setVariable(expression.name, stringWord[:match.end()], variables, pos)
     66 
     67     # Move cursor by deleting the matched characters.
     68     stringWord = stringWord[match.end():]
     69 
     70   # Make sure the entire word matched, i.e. `stringWord` is empty.
     71   if stringWord:
     72     return None
     73 
     74   return variables
     75 
     76 def MatchLines(checkerLine, stringLine, variables):
     77   """ Attempts to match a CHECK line against a string. Returns variable state
     78       after the match if successful and None otherwise.
     79   """
     80   assert checkerLine.variant != TestAssertion.Variant.Eval
     81 
     82   checkerWords = splitAtSeparators(checkerLine.expressions)
     83   stringWords = stringLine.split()
     84 
     85   while checkerWords:
     86     # Get the next run of TestExpressions which must match one string word.
     87     checkerWord, checkerWords = headAndTail(checkerWords)
     88 
     89     # Keep reading words until a match is found.
     90     wordMatched = False
     91     while stringWords:
     92       stringWord, stringWords = headAndTail(stringWords)
     93       newVariables = matchWords(checkerWord, stringWord, variables, checkerLine)
     94       if newVariables is not None:
     95         wordMatched = True
     96         variables = newVariables
     97         break
     98     if not wordMatched:
     99       return None
    100 
    101   # All TestExpressions matched. Return new variable state.
    102   return variables
    103 
    104 def getEvalText(expression, variables, pos):
    105   if expression.variant == TestExpression.Variant.PlainText:
    106     return expression.text
    107   else:
    108     assert expression.variant == TestExpression.Variant.VarRef
    109     return getVariable(expression.name, variables, pos)
    110 
    111 def EvaluateLine(checkerLine, variables):
    112   assert checkerLine.variant == TestAssertion.Variant.Eval
    113   eval_string = "".join(map(lambda expr: getEvalText(expr, variables, checkerLine),
    114                             checkerLine.expressions))
    115   return eval(eval_string)
    116