import { nextGlobalNameSupply } from "../Compile"; import { GenState, initState, Name, Scope, showName } from "../GenState"; import * as State from "../StateMonad"; import { ColName } from "../Types"; export class Query implements PromiseLike { /** * This is what Query is really about */ public unQ: State.State; protected dummy: [Query, s, a]; public constructor(fn: (resolve: (y: State.State | Query) => void) => void) { fn(x => this.resolve(x)); } public then( onfulfilled?: ((value: a) => TResult1 | PromiseLike) | undefined | null) : Query { if (onfulfilled === null || onfulfilled === undefined) { throw new Error("missing onfulfilled"); } console.log("then"); const onfulfilled2: ((value: a) => TResult1 | Query) = onfulfilled; return new Query((resolve: (y: State.State) => void) => { // tslint:disable-next-line:strict-type-predicates if (this.unQ === null) { throw new Error("Invalid State"); } resolve(State.bind(this.unQ, (x: a): State.State => { const y = onfulfilled2(x); if (y instanceof Query) { return y.unQ; } else { return State.pure(y); } })); }); } private resolve(result: State.State | Query): void { if (result instanceof Query) { result.then(x => { console.log("x", typeof x, x); this.resolve(State.pure(x)); // TODO Is this correct??? }); } else { this.unQ = result; } } } /** * Run a query computation from an initial state. */ export function runQueryM(scope: Scope, query: Query): [a, GenState] { return query.unQ.runState(initState(scope)); } export function queryPure(a: a): Query { return new Query(resolve => { resolve(State.pure(a)); }); } export function queryBind(lhs: Query, rhs: (x: a) => Query): Query { // tslint:disable-next-line:strict-type-predicates if (lhs.unQ === undefined) { console.log("queryBind Query not ready"); } return new Query(resolve => { resolve(State.bind(lhs.unQ, (x: a) => rhs(x).unQ)); }); } /** * Run a query computation in isolation, but reusing the current name supply. */ export function isolate(q: Query): State.State { return State.bind( State.get(), st => State.bind( State.put( initState(st.nameScope) ), () => State.bind( q.unQ, x => State.bind( State.get(), st2 => State.bind( State.put(st), () => State.pure([st2, x]) ) ) ) ) ); } /** * Get a guaranteed unique identifier. */ export function freshId(): State.State { return State.bind( State.get(), st => State.pure({ scope: st.nameScope, ident: nextGlobalNameSupply() }) ); } /** * Get a guaranteed unique column name. */ export function freshName(): State.State { return State.bind( freshId(), n => State.pure(ColName.wrap("tmp_" + showName(n))) ); }