def compile_Set( expr: qlast.Base, *, ctx: context.ContextLevel) -> irast.Base: if expr.elements: if len(expr.elements) == 1: # From the scope perspective, single-element set # literals are equivalent to a binary UNION with # an empty set, not to the element. with ctx.newscope(fenced=True) as scopectx: ir_set = dispatch.compile(expr.elements[0], ctx=scopectx) return setgen.scoped_set(ir_set, ctx=scopectx) else: elements = flatten_set(expr) # a set literal is just sugar for a UNION op = qlast.UNION bigunion = qlast.BinOp( left=elements[0], right=elements[1], op=op ) for el in elements[2:]: bigunion = qlast.BinOp( left=bigunion, right=el, op=op ) return dispatch.compile(bigunion, ctx=ctx) else: return irutils.new_empty_set(ctx.schema, alias=ctx.aliases.get('e'))
def _join_expressions(self, exprs, op='AND'): if not exprs: return None elif len(exprs) == 1: return exprs[0] result = qlast.BinOp(left=exprs[0], op=op, right=exprs[1]) for expr in exprs[2:]: result = qlast.BinOp(left=result, op=op, right=expr) return result
def visit_TypeCheckOp(self, node): result = qlast.BinOp() result.left = self.visit(node.left) # Trim the trailing __type__ added by the compiler result.left.steps = result.left.steps[:-1] result.right = self.visit(node.right) result.op = node.op return result
def extend_qlbinop(binop, *exprs, op=ast.ops.AND): exprs = list(exprs) binop = binop or exprs.pop(0) for expr in exprs: if expr is not binop: binop = qlast.BinOp(left=binop, right=expr, op=op) return binop
def reduce_Expr_OP_Expr(self, *kids): op = kids[1].val if op == '!=': op = ast.ops.NE elif op == '=': op = ast.ops.EQ elif op == '>=': op = ast.ops.GE elif op == '<=': op = ast.ops.LE elif op == '?=': op = qlast.EQUIVALENT elif op == '?!=': op = qlast.NEQUIVALENT self.val = qlast.BinOp(left=kids[0].val, op=op, right=kids[2].val)
def visit_OperatorCall(self, node): args = node.args if node.operator_kind is ft.OperatorKind.INFIX: result = qlast.BinOp( left=self.visit(args[0]), right=self.visit(args[1]), op=node.func_shortname.name, ) elif node.operator_kind is ft.OperatorKind.PREFIX: result = qlast.UnaryOp( operand=self.visit(args[0]), op=node.func_shortname.name, ) else: raise RuntimeError( f'unexpected operator kind: {node.operator_kind}') return result
def visit_ObjectField(self, node): fname = node.name # handle boolean ops if fname == 'and': return self._visit_list_of_inputs(node.value.value, ast.ops.AND) elif fname == 'or': return self._visit_list_of_inputs(node.value.value, ast.ops.OR) elif fname == 'not': return qlast.UnaryOp(op=ast.ops.NOT, operand=self.visit(node.value)) # handle various scalar ops op = gt.GQL_TO_OPS_MAP.get(fname) if op: value = self.visit(node.value) return qlast.BinOp(left=self._context.filter, op=op, right=value) # we're at the beginning of a scalar op _, target = self._get_parent_and_current_type() name = self.get_path_prefix() name.append(qlast.Ptr(ptr=qlast.ObjectRef(name=fname))) name = qlast.Path(steps=name) # potentially need to cast the 'name' side into a <str>, so as # to be compatible with the 'value' typename = target.get_field_type(fname).short_name if (typename != 'str' and gt.EDB_TO_GQL_SCALARS_MAP[typename] in {GraphQLString, GraphQLID}): name = qlast.TypeCast( expr=name, type=qlast.TypeName(maintype=qlast.ObjectRef(name='str')), ) self._context.filter = name return self.visit(node.value)
def visit_Argument(self, node, *, get_path_prefix): op = ast.ops.EQ name_parts = node.name _, target = self._get_parent_and_current_type() name = get_path_prefix() name.append(qlast.Ptr(ptr=qlast.ObjectRef(name=name_parts))) name = qlast.Path(steps=name) value = self.visit(node.value) # potentially need to cast the 'name' side into a <str>, so as # to be compatible with the 'value' typename = target.get_field_type(name_parts).short_name if (typename != 'str' and gt.EDB_TO_GQL_SCALARS_MAP[typename] in {GraphQLString, GraphQLID}): name = qlast.TypeCast( expr=name, type=qlast.TypeName(maintype=qlast.ObjectRef(name='str')), ) return qlast.BinOp(left=name, op=op, right=value)
def reduce_Expr_OR_Expr(self, *kids): self.val = qlast.BinOp(left=kids[0].val, op=kids[1].val.upper(), right=kids[2].val)
def reduce_Expr_EQUALS_Expr(self, *kids): self.val = qlast.BinOp(left=kids[0].val, op=kids[1].val, right=kids[2].val)
def reduce_Expr_RANGBRACKET_Expr(self, *kids): self.val = qlast.BinOp(left=kids[0].val, op=kids[1].val, right=kids[2].val)
def reduce_Expr_CIRCUMFLEX_Expr(self, *kids): self.val = qlast.BinOp(left=kids[0].val, op=kids[1].val, right=kids[2].val)
def reduce_Expr_DOUBLESLASH_Expr(self, *kids): self.val = qlast.BinOp(left=kids[0].val, op=kids[1].val, right=kids[2].val)
def visit_BinOp(self, node): result = qlast.BinOp() result.left = self.visit(node.left) result.right = self.visit(node.right) result.op = node.op return result
def reduce_Expr_IN_Expr(self, *kids): inexpr = kids[2].val self.val = qlast.BinOp(left=kids[0].val, op=ast.ops.IN, right=inexpr)
def reduce_Expr_LIKE_Expr(self, *kids): self.val = qlast.BinOp(left=kids[0].val, op='LIKE', right=kids[2].val)
def reduce_Expr_NOT_IN_Expr(self, *kids): inexpr = kids[3].val self.val = qlast.BinOp(left=kids[0].val, op='NOT IN', right=inexpr)
def reduce_Expr_LANGBRACKET_Expr(self, *kids): self.val = qlast.BinOp(left=kids[0].val, op=ast.ops.LT, right=kids[2].val)
def reduce_Expr_PERCENT_Expr(self, *kids): self.val = qlast.BinOp(left=kids[0].val, op=ast.ops.MOD, right=kids[2].val)
def reduce_Expr_SLASH_Expr(self, *kids): self.val = qlast.BinOp(left=kids[0].val, op=ast.ops.DIV, right=kids[2].val)
def reduce_Expr_MINUS_Expr(self, *kids): self.val = qlast.BinOp(left=kids[0].val, op=ast.ops.SUB, right=kids[2].val)
def compile_func_to_ir(func, schema, *, anchors=None, security_context=None, modaliases=None, implicit_id_in_shapes=False): """Compile an EdgeQL function into EdgeDB IR.""" if debug.flags.edgeql_compile: debug.header('EdgeQL Function') debug.print(func.get_code(schema)) trees = ql_parser.parse_block(func.get_code(schema) + ';') if len(trees) != 1: raise errors.InvalidFunctionDefinitionError( 'functions can only contain one statement') tree = trees[0] if modaliases: ql_parser.append_module_aliases(tree, modaliases) if anchors is None: anchors = {} anchors['__defaults_mask__'] = irast.Parameter( name='__defaults_mask__', stype=schema.get('std::bytes')) func_params = func.get_params(schema) pg_params = s_func.PgParams.from_params(schema, func_params) for pi, p in enumerate(pg_params.params): p_shortname = p.get_shortname(schema) anchors[p_shortname] = irast.Parameter(name=p_shortname, stype=p.get_type(schema)) if p.get_default(schema) is None: continue tree.aliases.append( qlast.AliasedExpr( alias=p_shortname, expr=qlast. IfElse(condition=qlast.BinOp(left=qlast.FunctionCall( func=('std', 'bytes_get_bit'), args=[ qlast.FuncArg(arg=qlast.Path( steps=[qlast.ObjectRef( name='__defaults_mask__')])), qlast.FuncArg(arg=qlast.IntegerConstant(value=str(pi))) ]), right=qlast.IntegerConstant( value='0'), op='='), if_expr=qlast.Path( steps=[qlast.ObjectRef(name=p_shortname)]), else_expr=qlast._Optional( expr=p.get_ql_default(schema))))) ir = compile_ast_to_ir(tree, schema, anchors=anchors, func=func, security_context=security_context, modaliases=modaliases, implicit_id_in_shapes=implicit_id_in_shapes) return ir
def reduce_Expr_NOT_ILIKE_Expr(self, *kids): self.val = qlast.BinOp(left=kids[0].val, op='NOT ILIKE', right=kids[3].val)
def reduce_Expr_OR_Expr(self, *kids): self.val = qlast.BinOp(left=kids[0].val, op=ast.ops.OR, right=kids[2].val)
def reduce_Expr_UNION_Expr(self, *kids): self.val = qlast.BinOp(left=kids[0].val, op='UNION', right=kids[2].val)
def reduce_Expr_IS_NOT_Expr(self, *kids): self.val = qlast.BinOp(left=kids[0].val, op=ast.ops.IS_NOT, right=kids[3].val)