def convert_any_all(node, state): if len(node.args) != 1 or node.keywords: raise ReizQLSyntaxError( f"Parameter mismatch for built-in function: {node.name!r}") check = compile_edgeql(*node.args, state) negated = isinstance(check, EdgeQLNot) if negated: check = check.value if isinstance(check, EdgeQLSelect) and check.filters: operator = EdgeQLComparisonOperator.EQUALS elif isinstance(check, EdgeQLSelect) and not check.filters: check = protected_name(check.name, prefix=True) operator = EdgeQLComparisonOperator.IDENTICAL else: raise ReizQLSyntaxError( "Unsupported operation passed into built-in function") if negated: operator = operator.negate() return EdgeQLFilter( EdgeQLCall( node.name.lower(), [EdgeQLFilter(EdgeQLFilterKey(state.pointer), check, operator)], ), EdgeQLPreparedQuery("True"), )
def generate_typechecked_query_item(query, base): rec_list = False if isinstance(query.key, EdgeQLCall) and isinstance( query.key.args[0], EdgeQLFilterKey): name = query.key.args[0].name rec_list = True elif isinstance(query.key, EdgeQLFilterKey): name = query.key.name else: raise ReizQLSyntaxError( f"Unknown matcher type for list expression: {type(query).__name__}" ) key = EdgeQLAttribute(base, name) if rec_list: query.key.args[0] = key return query elif isinstance(query.value, EdgeQLPreparedQuery): query.key = key return query elif isinstance(query.value, EdgeQLSelect): model = protected_name(query.value.name, prefix=True) verifier = EdgeQLVerify(key, EdgeQLVerifyOperator.IS, model) if query.value.filters: return generate_typechecked_query(query.value.filters, verifier) else: return EdgeQLFilter( EdgeQLAttribute(base, query.key.name), model, EdgeQLComparisonOperator.IDENTICAL, ) else: raise ReizQLSyntaxError("Unsupported syntax")
def convert_list(node, state): object_verifier = EdgeQLFilter( EdgeQLCall("count", [EdgeQLFilterKey(state.pointer)]), len(node.items)) if len(node.items) == 0 or all(item is ReizQLIgnore for item in node.items): return object_verifier assignments = {} select_filters = None for index, item in enumerate(node.items): if item is ReizQLIgnore: continue elif not isinstance(item, ReizQLMatch): raise ReizQLSyntaxError( "A list may only contain matchers, not atoms") selection = EdgeQLSelect( EdgeQLFilterKey(state.pointer), ordered=EdgeQLProperty("index"), offset=index, limit=1, ) filters = convert_match(item).filters # If there are no value queries, only type-check name = f"__item_{index}_{id(filters)}" if filters is None: assignments[name] = selection select_filters = merge_filters( select_filters, EdgeQLFilter( EdgeQLName(name), protected_name(item.name, prefix=True), EdgeQLComparisonOperator.IDENTICAL, ), ) else: assignments[name] = EdgeQLVerify( selection, EdgeQLVerifyOperator.IS, protected_name(item.name, prefix=True), ) select_filters = merge_filters( select_filters, generate_typechecked_query(filters, name), ) if assignments: with_block = EdgeQLWithBlock(assignments) else: with_block = None value_verifier = EdgeQLSelect( select_filters, with_block=with_block, ) return EdgeQLFilterChain( object_verifier, value_verifier, )
def parse_unary(self, node): if isinstance(node.op, ast.Not): return grammar.Not(self.parse(node.operand)) elif isinstance(node.op, ast.Invert): ensure(isinstance(node.operand, ast.Name)) return grammar.Ref(node.operand.id) else: raise ReizQLSyntaxError.from_node(node, "unknown unary operator")
def generate_typechecked_query(filters, base): base_query = None for query, operator in unpack_filters(filters): if isinstance(query, EdgeQLSelect): current_query = generate_typechecked_selection(query, base) elif isinstance(query, EdgeQLFilter): current_query = generate_typechecked_query_item(query, base) else: raise ReizQLSyntaxError("Unsupported syntax") base_query = merge_filters(base_query, current_query, operator) return base_query
def get_ordered_parents(self): parents = self.parents + [self] enumeration_start = self.get_property("enumeration start depth") if enumeration_start is None: return parents for index, parent in enumerate(parents): if parent.depth == enumeration_start: break else: raise ReizQLSyntaxError( "compiler check failed: no enumeration start block found!" ) return parents[index:]
def parse_binop(self, node): if isinstance(node.op, ast.BitOr): operator = grammar.LogicOperator.OR elif isinstance(node.op, ast.BitAnd): operator = grammar.LogicOperator.AND else: raise ReizQLSyntaxError.from_node( node.op, f"Unknown logical operation: {type(node.op).__name__}") return grammar.LogicalOperation( left=self.parse(node.left), right=self.parse(node.right), operator=operator, )
def parse_query(source): if isinstance(source, bytes): source = source.decode() try: tree = ast.parse(source) except SyntaxError as exc: raise ReizQLSyntaxError(exc.args[0]) ensure(len(tree.body) == 1) ensure(isinstance(tree.body[0], ast.Expr), tree.body[0]) ensure(isinstance(tree.body[0].value, ast.Call), tree.body[0].value) parser = Parser(source) root_node = parser.parse(tree.body[0].value) ensure(isinstance(root_node, grammar.Match), tree.body[0]) ensure(root_node.positional, tree.body[0]) return root_node
def parse(self, node): raise ReizQLSyntaxError.from_node(node, "Invalid syntax")
def ensure(condition, node=None, message="Invalid syntax"): if not condition: if node is None: raise ReizQLSyntaxError(message) else: raise ReizQLSyntaxError.from_node(node, message)
def verify(self): for definition, (scope, _) in self.definitions.items(): if scope.reference_counts[definition] < 1: raise ReizQLSyntaxError(f"unused reference: {definition!r}")
def compile_edgeql(obj, state): raise ReizQLSyntaxError(f"Unexpected query object: {obj!r}")
def ensure(self, node, condition): if not condition: raise ReizQLSyntaxError(f"compiler check failed for: {node!r}")