def get_params_symtable( params: FuncParameterList, schema: s_schema.Schema, *, inlined_defaults: bool, ) -> Dict[str, qlast.Expr]: anchors: Dict[str, qlast.Expr] = {} defaults_mask = qlast.TypeCast( expr=qlast.Parameter(name='__defaults_mask__', optional=False), type=qlast.TypeName( maintype=qlast.ObjectRef( module='std', name='bytes', ), ), ) for pi, p in enumerate(params.get_in_canonical_order(schema)): p_shortname = p.get_parameter_name(schema) p_is_optional = p.get_typemod(schema) is not ft.TypeModifier.SINGLETON anchors[p_shortname] = qlast.TypeCast( expr=qlast.Parameter( name=p_shortname, optional=p_is_optional, ), type=utils.typeref_to_ast(schema, p.get_type(schema)), ) p_default = p.get_default(schema) if p_default is None: continue if not inlined_defaults: continue anchors[p_shortname] = qlast.IfElse( condition=qlast.BinOp( left=qlast.FunctionCall( func=('std', 'bytes_get_bit'), args=[ defaults_mask, qlast.IntegerConstant(value=str(pi)), ]), op='=', right=qlast.IntegerConstant(value='0'), ), if_expr=anchors[p_shortname], else_expr=qlast._Optional(expr=p_default.qlast), ) return anchors
def visit_OperatorCall(self, node): args = node.args if node.operator_kind is ft.OperatorKind.INFIX: result = qlast.BinOp( left=self.visit(args[0].expr), right=self.visit(args[1].expr), op=node.func_shortname.name, ) elif node.operator_kind is ft.OperatorKind.PREFIX: result = qlast.UnaryOp( operand=self.visit(args[0].expr), op=node.func_shortname.name, ) elif node.func_shortname == 'std::IF': result = qlast.IfElse() result.condition = self.visit(args[0].expr) result.if_expr = self.visit(args[1].expr) result.else_expr = self.visit(args[2].expr) else: raise RuntimeError( f'unexpected operator kind: {node.operator_kind}') return result
def compile_func_to_ir(func, schema, *, anchors=None, security_context=None, modaliases=None, implicit_id_in_shapes=False, implicit_tid_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__', typeref=irtyputils.type_to_typeref(schema, 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, typeref=irtyputils.type_to_typeref(schema, 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, implicit_tid_in_shapes=implicit_tid_in_shapes) return ir
def reduce_Expr_IF_Expr_ELSE_Expr(self, *kids): self.val = qlast.IfElse(if_expr=kids[0].val, condition=kids[2].val, else_expr=kids[4].val)
def _get_general_offset_limit(self, after, before, first, last): # convert any static values to corresponding qlast if after is not None: if isinstance(after, qlast.Base): after = qlast.TypeCast(type=qlast.TypeName( maintype=qlast.ObjectRef(name='int64')), expr=after) else: after = qlast.BaseConstant.from_python(after) if before is not None: if isinstance(before, qlast.Base): before = qlast.TypeCast(type=qlast.TypeName( maintype=qlast.ObjectRef(name='int64')), expr=before) else: before = qlast.BaseConstant.from_python(before) if first is not None and not isinstance(first, qlast.Base): first = qlast.BaseConstant.from_python(first) if last is not None and not isinstance(last, qlast.Base): last = qlast.BaseConstant.from_python(last) offset = limit = None # convert before, after, first and last into offset and limit if after is not None: # The +1 is to make 'after' into an appropriate index. # # 0--a--1--b--2--c--3-- ... we call element at # index 0 (or "element 0" for short), the element # immediately after the mark 0. So after "element # 0" really means after "index 1". offset = qlast.BinOp(left=after, op='+', right=qlast.IntegerConstant(value='1')) if before is not None: # limit = before - (after or 0) if after: limit = qlast.BinOp(left=before, op='-', right=after) else: limit = before if first is not None: if limit is None: limit = first else: limit = qlast.IfElse(if_expr=first, condition=qlast.BinOp(left=first, op='<', right=limit), else_expr=limit) if last is not None: if limit is not None: if offset: offset = qlast.BinOp(left=offset, op='+', right=qlast.BinOp(left=limit, op='-', right=last)) else: offset = qlast.BinOp(left=limit, op='-', right=last) limit = qlast.IfElse(if_expr=last, condition=qlast.BinOp(left=last, op='<', right=limit), else_expr=limit) else: # FIXME: there wasn't any limit, so we can define last # in terms of offset alone without negative OFFSET # implementation raise g_errors.GraphQLTranslationError( f'last translates to a negative OFFSET in ' f'EdgeQL which is currently unsupported') return offset, limit