def solve_cast(expr, vars): """Get cast LHS to RHS.""" lhs = solve(expr.lhs, vars).value t = solve(expr.rhs, vars).value if t is None: raise errors.EfilterTypeError(root=expr, query=expr.source, message="Cannot find type named %r." % expr.rhs.value) if not isinstance(t, type): raise errors.EfilterTypeError( root=expr.rhs, query=expr.source, message="%r is not a type and cannot be used with 'cast'." % (t, )) try: cast_value = t(lhs) except TypeError: raise errors.EfilterTypeError(root=expr, query=expr.source, message="Invalid cast %s -> %s." % (type(lhs), t)) return Result(cast_value, ())
def __nest_scope(expr, outer, inner): try: return scope.ScopeStack(outer, inner) except TypeError: if protocol.implements(inner, applicative.IApplicative): raise errors.EfilterTypeError( root=expr, query=expr.source, message="Attempting to use a function %r as an object." % inner) raise errors.EfilterTypeError( root=expr, query=expr.source, message="Attempting to use %r as an object (IStructured)." % inner)
def visit_BinaryExpression(self, expr, **kwargs): lhst = self.visit(expr.lhs, **kwargs) if not protocol.isa(lhst, expr.type_signature[0]): raise errors.EfilterTypeError(query=self.query, root=expr.lhs, expected=expr.type_signature[0], actual=lhst) rhst = self.visit(expr.rhs, **kwargs) if not protocol.isa(rhst, expr.type_signature[1]): raise errors.EfilterTypeError(query=self.query, root=expr.rhs, expected=expr.type_signature[1], actual=rhst) return expr.return_signature
def validate(expr, scope): lhs_type = infer_type.infer_type(expr.lhs, scope) if not (lhs_type is protocol.AnyType or protocol.isa(lhs_type, expr.type_signature[0])): raise errors.EfilterTypeError(root=expr.lhs, expected=expr.type_signature[0], actual=lhs_type) rhs_type = infer_type.infer_type(expr.rhs, scope) if not (lhs_type is protocol.AnyType or protocol.isa(rhs_type, expr.type_signature[1])): raise errors.EfilterTypeError(root=expr.rhs, expected=expr.type_signature[1], actual=rhs_type) return True
def solve_var(expr, vars): """Returns the value of the var named in the expression.""" try: return Result(structured.resolve(vars, expr.value), ()) except (KeyError, AttributeError) as e: # Raise a better exception for accessing a non-existent member. raise errors.EfilterKeyError(root=expr, key=expr.value, message=e, query=expr.source) except (TypeError, ValueError) as e: # Raise a better exception for what is probably a null pointer error. if vars.locals is None: raise errors.EfilterNoneError( root=expr, query=expr.source, message="Trying to access member %r of a null." % expr.value) else: raise errors.EfilterTypeError(root=expr, query=expr.source, message="%r (vars: %r)" % (e, vars)) except NotImplementedError as e: raise errors.EfilterError( root=expr, query=expr.source, message="Trying to access member %r of an instance of %r." % (expr.value, type(vars)))
def validate(expr, scope): t = infer_type.infer_type(expr.value, scope) if not protocol.isa(t, boolean.IBoolean): raise errors.EfilterTypeError(root=expr, actual=t, expected=boolean.IBoolean) return True
def visit_LetAny(self, expr, **kwargs): t = self.visit_Let(expr, **kwargs) if not protocol.isa(t, boolean.IBoolean): raise errors.EfilterTypeError(query=self.query, root=expr, actual=t, expected=associative.IBoolean) return boolean.IBoolean
def visit_Let(self, expr, scope=None, **kwargs): t = self.visit(expr.context, scope=scope, **kwargs) if not (t is protocol.AnyType or protocol.isa(t, associative.IAssociative)): raise errors.EfilterTypeError(query=self.query, root=expr, actual=t, expected=associative.IAssociative) return self.visit(expr.expression, scope=t, **kwargs)
def solve_repeat(expr, vars): """Build a repeated value from subexpressions.""" try: result = repeated.meld(*[solve(x, vars).value for x in expr.children]) return Result(result, ()) except TypeError: raise errors.EfilterTypeError( root=expr, query=expr.source, message="All values in a repeated value must be of the same type.")
def solve_let(expr, vars): """Solves a let-form by calling RHS with nested scope.""" lhs_value = solve(expr.lhs, vars).value if not isinstance(lhs_value, structured.IStructured): raise errors.EfilterTypeError( root=expr.lhs, query=expr.original, message="The LHS of 'let' must evaluate to an IStructured. Got %r." % (lhs_value,)) return solve(expr.rhs, __nest_scope(expr.lhs, vars, lhs_value))
def visit_VariadicExpression(self, expr, **kwargs): for subexpr in expr.children: t = self.visit(subexpr, **kwargs) if not protocol.isa(t, expr.type_signature): raise errors.EfilterTypeError(query=self.query, root=subexpr, expected=expr.type_signature, actual=t) return expr.return_signature
def validate(expr, scope): for subexpr in expr.children: validate(subexpr, scope) t = infer_type.infer_type(subexpr, scope) if not (t is protocol.AnyType or protocol.isa(t, expr.type_signature)): raise errors.EfilterTypeError(root=subexpr, expected=expr.type_signature, actual=t) return True
def solve_isinstance(expr, vars): """Typecheck whether LHS is type on the RHS.""" lhs = solve(expr.lhs, vars) try: t = solve(expr.rhs, vars).value except errors.EfilterKeyError: t = None if t is None: raise errors.EfilterTypeError(root=expr.rhs, query=expr.source, message="Cannot find type named %r." % expr.rhs.value) if not isinstance(t, type): raise errors.EfilterTypeError( root=expr.rhs, query=expr.source, message="%r is not a type and cannot be used with 'isa'." % (t, )) return Result(protocol.implements(lhs.value, t), ())
def validate(expr, scope): # Make sure there's an ELSE block. if expr.default() is None: raise errors.EfilterLogicError( root=expr, message="Else blocks are required in EFILTER.") # Make sure conditions evaluate to IBoolean. for condition, _ in expr.conditions(): t = infer_type.infer_type(condition, scope) if not protocol.isa(t, boolean.IBoolean): raise errors.EfilterTypeError(root=expr, actual=t, expected=boolean.IBoolean)
def solve_sum(expr, vars): total = 0 for child in expr.children: val = __solve_for_scalar(child, vars) try: total += val except TypeError: raise errors.EfilterTypeError(expected=number.INumber, actual=type(val), root=child, query=expr.source) return Result(total, ())
def solve_product(expr, vars): product = 1 for child in expr.children: val = __solve_for_scalar(child, vars) try: product *= val except TypeError: raise errors.EfilterTypeError(expected=number.INumber, actual=type(val), root=child, query=expr.source) return Result(product, ())
def __solve_for_scalar(expr, vars): """Helper: solve 'expr' always returning a scalar (not IRepeated). If the output of 'expr' is a single value or a single RowTuple with a single column then return the value in that column. Otherwise raise. Arguments: expr: Expression to solve. vars: The scope. Returns: A scalar value (not an IRepeated). Raises: EfilterTypeError if it cannot get a scalar. """ var = solve(expr, vars).value try: scalar = repeated.getvalue(var) except TypeError: raise errors.EfilterTypeError( root=expr, query=expr.source, message="Wasn't expecting more than one value here. Got %r." % (var, )) if isinstance(scalar, row_tuple.RowTuple): try: return scalar.get_singleton() except ValueError: raise errors.EfilterTypeError( root=expr, query=expr.source, message="Was expecting a scalar value here. Got %r." % (scalar, )) else: return scalar
def __solve_and_destructure_repeated(expr, vars): """Helper: solve 'expr' always returning a list of scalars. If the output of 'expr' is one or more row tuples with only a single column then return a repeated value of values in that column. If there are more than one column per row then raise. This returns a list because there's no point in wrapping the scalars in a repeated value for use internal to the implementing solver. Returns: Two values: - An iterator (not an IRepeated!) of scalars. - A boolean to indicate whether the original value was repeating. Raises: EfilterTypeError if the values don't conform. """ iterable, isrepeating = __solve_for_repeated(expr, vars) if iterable is None: return (), isrepeating if not isrepeating: return [iterable], False values = iter(iterable) try: value = next(values) except StopIteration: return (), True if not isinstance(value, row_tuple.RowTuple): result = [value] # We skip type checking the remaining values because it'd be slow. result.extend(values) return result, True try: result = [value.get_singleton()] for value in values: result.append(value.get_singleton()) return result, True except ValueError: raise errors.EfilterTypeError( root=expr, query=expr.source, message="Was expecting exactly one column in %r." % (value, ))
def visit_Membership(self, expr, **kwargs): symbols = set() lha = self.visit(expr.lhs, **kwargs) rha = self.visit(expr.rhs, **kwargs) symbols.update(lha.symbols) symbols.update(rha.symbols) if (not isinstance(expr.rhs, expression.Literal) or not isinstance(expr.lhs, expression.Binding)): return Analysis(symbols, ()) if not protocol.implements(expr.rhs.value, iset.ISet): # Yup, no can do. raise errors.EfilterTypeError(root=expr.rhs, query=self.query, actual=type(expr.rhs.value), expected=iset.ISet) return Analysis(symbols, (expr.lhs.value, ))
def solve_quotient(expr, vars): children = enumerate(expr.children) _, first_child = next(children) quotient = __solve_for_scalar(first_child, vars) for idx, child in children: val = __solve_for_scalar(child, vars) try: quotient /= val except TypeError: # The type what caused that there error. if idx == 1: actual_t = type(quotient) else: actual_t = type(val) raise errors.EfilterTypeError(expected=number.INumber, actual=actual_t, root=expr.children[idx - 1], query=expr.source) return Result(quotient, ())
def solve_partialorderedset(expr, vars): iterator = iter(expr.children) min_ = __solve_for_scalar(next(iterator), vars) if min_ is None: return Result(False, ()) for child in iterator: val = __solve_for_scalar(child, vars) try: if min_ < val or val is None: return Result(False, ()) except TypeError: raise errors.EfilterTypeError(expected=type(min_), actual=type(val), root=child, query=expr.source) min_ = val return Result(True, ())
def convert_to_list(expr, repeated_list): if not repeated.isrepeating(repeated_list): return [repeated_list] result = [] for element in repeated_list: if element is not None: # The output from a select is a repeated structured # (dict). If it has a single member we just use that, # otherwise we raise because the query is probably bad # (it should only return a single column). if structured.isstructured(element): members = structured.getmembers(element) if len(members) != 1: raise errors.EfilterTypeError( message="Expecting a single column in subselect - " "got %s columns" % len(members), query=expr.source) element = structured.resolve(element, members[0]) result.append(element) return result