Source: cst-convert.mjs

// Universal CST converter dispatch (issue #138).
//
// Single entry point that turns host-language source into a `.lino` CST and
// back. Provides:
//
//   - `parseToCst(src, lang)` — host source → CST.
//   - `printFromCst(node, lang)` — CST → host source.
//   - `roundTrip(src, lang)` — convenience helper that asserts byte fidelity.
//
// Supported `lang` values: `'rust'`, `'js'`, `'lean'`, `'rocq'`.

import { parseRust, printRust } from './cst-rust.mjs';
import { parseJs, printJs } from './cst-js.mjs';
import { parseLean, printLean } from './cst-lean.mjs';
import { parseRocq, printRocq } from './cst-rocq.mjs';

const PARSERS = {
  rust: parseRust,
  js: parseJs,
  javascript: parseJs,
  lean: parseLean,
  rocq: parseRocq,
};

const PRINTERS = {
  rust: printRust,
  js: printJs,
  javascript: printJs,
  lean: printLean,
  rocq: printRocq,
};

/**
 * The four host languages plus their aliases.
 * @type {ReadonlyArray<'rust' | 'js' | 'javascript' | 'lean' | 'rocq'>}
 */
export const SUPPORTED_LANGUAGES = Object.freeze(['rust', 'js', 'javascript', 'lean', 'rocq']);

/**
 * Parse host-language source into a `.lino` CST.
 *
 * @param {string} src host-language source.
 * @param {'rust'|'js'|'javascript'|'lean'|'rocq'} lang
 * @returns {CstNode}
 */
export function parseToCst(src, lang) {
  const parse = PARSERS[lang];
  if (!parse) throw new Error(`unsupported language for parseToCst: ${lang}`);
  return parse(src);
}

/**
 * Print a CST node back to host-language source.
 *
 * @param {CstNode} node CST tree.
 * @param {'rust'|'js'|'javascript'|'lean'|'rocq'} lang
 * @returns {string}
 */
export function printFromCst(node, lang) {
  const print = PRINTERS[lang];
  if (!print) throw new Error(`unsupported language for printFromCst: ${lang}`);
  return print(node);
}

/**
 * Verify that `printFromCst(parseToCst(src, lang), lang) === src`.
 *
 * @param {string} src host-language source.
 * @param {'rust'|'js'|'javascript'|'lean'|'rocq'} lang
 * @returns {{ ok: boolean, source: string, roundTripped: string }}
 */
export function roundTrip(src, lang) {
  const cst = parseToCst(src, lang);
  const roundTripped = printFromCst(cst, lang);
  return { ok: roundTripped === src, source: src, roundTripped };
}