def _ParseTerm(self, must=False): """Parses a [-]<key> <operator> <operand> term. Args: must: Raises ExpressionSyntaxError if must is True and there is no expression. Raises: ExpressionSyntaxError: The expression has a syntax error. Returns: The new backend expression tree. """ here = self._lex.GetPosition() if not self._lex.SkipSpace(): if must: raise resource_exceptions.ExpressionSyntaxError( 'Term expected [{0}].'.format(self._lex.Annotate(here))) return None # Check for end of (...) term. if self._lex.IsCharacter(')', peek=True): # The caller will determine if this ends (...) or is a syntax error. return None # Check for start of (...) term. if self._lex.IsCharacter('('): self._parenthesize.append(set()) tree = self._ParseExpr() # Either the next char is ')' or we hit an end of expression syntax error. self._lex.IsCharacter(')') self._parenthesize.pop() return tree # Check for term inversion. invert = self._lex.IsCharacter('-') # Parse the key. key, transform = self._ParseKey() # Parse the operator. here = self._lex.GetPosition() operator = self._ParseOperator() if not operator: if transform and not key: # A global restriction function. tree = self._backend.ExprGlobal(transform) elif not transform and len(key) == 1: # A global restriction on key[0]. func_name = 'global' func = self._defaults.symbols.get(func_name, None) if not func: raise resource_exceptions.ExpressionSyntaxError( 'Global restriction not supported [{0}].'.format( self._lex.Annotate(here))) transform = resource_lex.MakeTransform(func_name, func, args=key, restriction=True) tree = self._backend.ExprGlobal(transform) else: raise resource_exceptions.ExpressionSyntaxError( 'Operator expected [{0}].'.format( self._lex.Annotate(here))) if invert: tree = self._backend.ExprNOT(tree) return tree # Parse the operand. self._lex.SkipSpace(token='Operand') here = self._lex.GetPosition() if any([self._lex.IsString(x) for x in self._LOGICAL]): raise resource_exceptions.ExpressionSyntaxError( 'Logical operator not expected [{0}].'.format( self._lex.Annotate(here))) # The '=' and ':' operators accept '('...')' list operands. if (operator in (self._backend.ExprEQ, self._backend.ExprHAS) and self._lex.IsCharacter('(')): # List valued operand. operand = self._lex.Args(separators=' \t\n,') else: operand = self._lex.Token('()') if operand is None: raise resource_exceptions.ExpressionSyntaxError( 'Term operand expected [{0}].'.format( self._lex.Annotate(here))) # Make an Expr node for the term. tree = operator(key=key, operand=self._backend.ExprOperand(operand), transform=transform) if invert: tree = self._backend.ExprNOT(tree) return tree
def _ParseTerm(self, must=False): """Parses a [-]<key> <operator> <operand> term. Args: must: Raises ExpressionSyntaxError if must is True and there is no expression. Raises: ExpressionSyntaxError: The expression has a syntax error. Returns: The new backend expression tree. """ here = self._lex.GetPosition() if not self._lex.SkipSpace(): if must: raise resource_exceptions.ExpressionSyntaxError( 'Term expected [{0}].'.format(self._lex.Annotate(here))) return None # Check for end of (...) term. if self._lex.IsCharacter(')', peek=True): # The caller will determine if this ends (...) or is a syntax error. return None # Check for start of (...) term. if self._lex.IsCharacter('('): self._parenthesize.append(set()) tree = self._ParseExpr() # Either the next char is ')' or we hit an end of expression syntax error. self._lex.IsCharacter(')') self._parenthesize.pop() return tree # Check for term inversion. invert = self._lex.IsCharacter('-') # Parse the key. here = self._lex.GetPosition() syntax_error = None try: key, transform = self._ParseKey() restriction = None except resource_exceptions.ExpressionSyntaxError as syntax_error: # An invalid key could be a global restriction. self._lex.SetPosition(here) restriction = self._lex.Token(resource_lex.OPERATOR_CHARS, space=False) transform = None key = None # Parse the operator. here = self._lex.GetPosition() operator = self._ParseOperator() if not operator: if transform and not key: # A global restriction function. tree = self._backend.ExprGlobal(transform) elif transform: # key.transform() must be followed by an operator. raise resource_exceptions.ExpressionSyntaxError( 'Operator expected [{0}].'.format(self._lex.Annotate(here))) elif restriction in ['AND', 'OR']: raise resource_exceptions.ExpressionSyntaxError( 'Term expected [{0}].'.format(self._lex.Annotate())) else: # A global restriction on key. if not restriction: restriction = resource_lex.GetKeyName(key, quote=False) pattern = re.compile(re.escape(restriction), re.IGNORECASE) name = resource_projection_spec.GLOBAL_RESTRICTION_NAME tree = self._backend.ExprGlobal( resource_lex.MakeTransform( name, self._defaults.symbols.get( name, resource_property.EvaluateGlobalRestriction), args=[restriction, pattern])) if invert: tree = self._backend.ExprNOT(tree) return tree elif syntax_error: raise syntax_error # pylint: disable=raising-bad-type # Parse the operand. self._lex.SkipSpace(token='Operand') here = self._lex.GetPosition() if any([self._lex.IsString(x) for x in self._LOGICAL]): raise resource_exceptions.ExpressionSyntaxError( 'Logical operator not expected [{0}].'.format( self._lex.Annotate(here))) # The '=' and ':' operators accept '('...')' list operands. if (operator in (self._backend.ExprEQ, self._backend.ExprHAS) and self._lex.IsCharacter('(')): # List valued operand. operand = [arg for arg in self._lex.Args(separators=' \t\n,') if arg not in self._LOGICAL] else: operand = self._lex.Token('()') if operand is None: raise resource_exceptions.ExpressionSyntaxError( 'Term operand expected [{0}].'.format(self._lex.Annotate(here))) # Make an Expr node for the term. tree = operator(key=key, operand=self._backend.ExprOperand(operand), transform=transform) if invert: tree = self._backend.ExprNOT(tree) return tree