import type { AnalysisContext, Ref } from '@hey-api/codegen-core'; import { ref } from '@hey-api/codegen-core'; import { py } from '../../py-compiler'; import type { MaybePyDsl } from '../base'; import { PyDsl } from '../base'; export type PyBinaryOperator = | '+' | '-' | '*' | '/' | '//' | '%' | '**' | '==' | '!=' | '>' | '>=' | '<' | '<=' | 'is' | 'is not' | 'in' | 'not in' | 'and' | 'or'; const Mixed = PyDsl; export class BinaryPyDsl extends Mixed { readonly '~dsl' = 'BinaryPyDsl'; protected _left?: Ref>; protected _op?: PyBinaryOperator; protected _right?: Ref>; constructor( left: MaybePyDsl, op: PyBinaryOperator, right: MaybePyDsl, ) { super(); this._left = ref(left); this._op = op; this._right = ref(right); } override analyze(ctx: AnalysisContext): void { super.analyze(ctx); ctx.analyze(this._left); ctx.analyze(this._right); } /** Returns true when all required builder calls are present. */ get isValid(): boolean { return !this.missingRequiredCalls().length; } and(right: MaybePyDsl): this { return this.opAndExpr('and', right); } div(right: MaybePyDsl): this { return this.opAndExpr('/', right); } eq(right: MaybePyDsl): this { return this.opAndExpr('==', right); } floordiv(right: MaybePyDsl): this { return this.opAndExpr('//', right); } gt(right: MaybePyDsl): this { return this.opAndExpr('>', right); } gte(right: MaybePyDsl): this { return this.opAndExpr('>=', right); } in_(right: MaybePyDsl): this { return this.opAndExpr('in', right); } is(right: MaybePyDsl): this { return this.opAndExpr('is', right); } isNot(right: MaybePyDsl): this { return this.opAndExpr('is not', right); } lt(right: MaybePyDsl): this { return this.opAndExpr('<', right); } lte(right: MaybePyDsl): this { return this.opAndExpr('<=', right); } minus(right: MaybePyDsl): this { return this.opAndExpr('-', right); } mod(right: MaybePyDsl): this { return this.opAndExpr('%', right); } neq(right: MaybePyDsl): this { return this.opAndExpr('!=', right); } notIn(right: MaybePyDsl): this { return this.opAndExpr('not in', right); } or(right: MaybePyDsl): this { return this.opAndExpr('or', right); } plus(right: MaybePyDsl): this { return this.opAndExpr('+', right); } pow(right: MaybePyDsl): this { return this.opAndExpr('**', right); } times(right: MaybePyDsl): this { return this.opAndExpr('*', right); } override toAst() { this.$validate(); return py.factory.createBinaryExpression( this.$node(this._left!), this._op!, this.$node(this._right!), ); } $validate(): asserts this is this & { _left: MaybePyDsl; _op: PyBinaryOperator; _right: MaybePyDsl; } { const missing = this.missingRequiredCalls(); if (!missing.length) return; throw new Error(`Binary expression missing ${missing.join(' and ')}`); } private missingRequiredCalls(): ReadonlyArray { const missing: Array = []; if (!this._left) missing.push('left operand'); if (!this._op) missing.push('operator'); if (!this._right) missing.push('right operand'); return missing; } private opAndExpr(op: PyBinaryOperator, right: MaybePyDsl): this { this._right = ref(right); this._op = op; return this; } }