import { Dictionary, KeyedSet, Position } from "@preserves/core"; import { refPosition } from "../reader"; import * as M from "../meta"; import { block, commas, Item, seq } from "./block"; export interface CompilerOptions { preservesModule?: string; defaultPointer?: M.Ref; warn?(message: string, pos: Position | null): void; } export class ModuleContext { readonly env: M.Environment; readonly schema: M.Schema; readonly options: CompilerOptions; readonly literals = new Dictionary(); readonly typedefs: Item[] = []; readonly functiondefs: Item[] = []; readonly imports = new KeyedSet<[string, string]>(); constructor(env: M.Environment, schema: M.Schema, options: CompilerOptions) { this.env = env; this.schema = schema; this.options = options; } literal(v: M.Input): Item { let varname = this.literals.get(v); if (varname === void 0) { const s = v.asPreservesText() .replace('_', '__') .replace('*', '_STAR_'); varname = M.isValidToken('_' + s, true) ? '$' + s : '__lit' + this.literals.size; this.literals.set(v, varname); } return varname; } derefPattern([_name, p]: [string, M.Alternative]): M.Definition { if (p.label === M.$ref) { return M.lookup(refPosition(p), p, this.env, (p) => p, (p) => p, (_modId, _modPath, pp) => pp ?? p); } else { return p; } } defineType(f: Item): void { this.typedefs.push(f); } defineFunction(f: (ctx: FunctionContext) => Item): void { this.functiondefs.push(f(new FunctionContext(this))); } } export class FunctionContext { readonly mod: ModuleContext; tempCounter = 0; temps: string[] = []; constructor(mod: ModuleContext) { this.mod = mod; } gentemp(): string { const varname = '_tmp' + this.tempCounter++; this.temps.push(varname); return varname; } gentemps(n: number): string[] { const temps = []; while (temps.length < n) temps.push(this.gentemp()); return temps; } block(f: () => Item[]): Item { const oldTemps = this.temps; this.temps = []; const items = f(); const ts = this.temps; this.temps = oldTemps; return block( ... ts.length > 0 ? [seq(`let `, commas(... ts), ': any')] : [], ... items); } }