diff --git a/packages/cxx-frontend/src/Parser.ts b/packages/cxx-frontend/src/Parser.ts index 1d3cedb4..55fb48a1 100644 --- a/packages/cxx-frontend/src/Parser.ts +++ b/packages/cxx-frontend/src/Parser.ts @@ -51,6 +51,7 @@ interface ParserParams { export class Parser { #unit: Unit | undefined; #ast: AST | undefined; + #pendingAST: Promise | undefined; static async init({ wasm, @@ -97,24 +98,54 @@ export class Parser { this.#unit = cxx.createUnit(source, path, { resolve, readFile }); } - async parse() { + async parse(): Promise { + return await this.getASTAsync(); + } + + async emitIR(): Promise { + const _ = await this.getASTAsync(); + return this.#unit?.emitIR() ?? ""; + } + + async #parseHelper(): Promise { + if (this.#pendingAST) { + return await this.#pendingAST; + } + if (!this.#unit) { - return; + throw new Error("Parser has been disposed"); } + await this.#unit.parse(); - this.#ast = AST.from(this.#unit.getHandle(), this); + + const ast = AST.from(this.#unit.getHandle(), this); + + if (!ast) { + throw new Error("Failed to create AST"); + } + + this.#ast = ast; + + return ast; } dispose() { this.#unit?.delete(); this.#unit = undefined; this.#ast = undefined; + this.#pendingAST = undefined; } getUnitHandle(): number { return this.#unit?.getUnitHandle() ?? 0; } + async getASTAsync(): Promise { + this.#pendingAST ??= this.#parseHelper(); + return await this.#pendingAST; + } + + // internal getAST(): AST | undefined { return this.#ast; } diff --git a/packages/cxx-frontend/src/Unit.ts b/packages/cxx-frontend/src/Unit.ts index 89c85b6b..9bb1f930 100644 --- a/packages/cxx-frontend/src/Unit.ts +++ b/packages/cxx-frontend/src/Unit.ts @@ -26,4 +26,5 @@ export interface Unit { getHandle(): number; getUnitHandle(): number; getDiagnostics(): Diagnostic[]; + emitIR(): string; } diff --git a/packages/cxx-frontend/src/cxx-js.d.ts b/packages/cxx-frontend/src/cxx-js.d.ts index 39b48241..63b044ed 100644 --- a/packages/cxx-frontend/src/cxx-js.d.ts +++ b/packages/cxx-frontend/src/cxx-js.d.ts @@ -101,6 +101,7 @@ export type CXX = { TranslationUnit: TranslationUnit; createUnit(source: string, path: string, api: Api): Unit; + emitIR(handle: number): string; getASTKind(handle: number): number; getASTSlot(handle: number, slot: number): number; getASTSlotKind(handle: number, slot: number): ASTSlotKind; diff --git a/src/frontend/CMakeLists.txt b/src/frontend/CMakeLists.txt index 10409ca0..6181afac 100644 --- a/src/frontend/CMakeLists.txt +++ b/src/frontend/CMakeLists.txt @@ -26,7 +26,6 @@ add_executable(cxx target_link_libraries(cxx PRIVATE cxx-lsp) if (CXX_ENABLE_MLIR) - target_compile_definitions(cxx PRIVATE CXX_WITH_MLIR) target_link_libraries(cxx PRIVATE cxx-mlir) endif() diff --git a/src/js/CMakeLists.txt b/src/js/CMakeLists.txt index b40d7d25..f05fa663 100644 --- a/src/js/CMakeLists.txt +++ b/src/js/CMakeLists.txt @@ -27,6 +27,10 @@ add_executable(cxx-js ${SOURCES}) target_link_libraries(cxx-js cxx-parser embind) +if (CXX_ENABLE_MLIR) + target_link_libraries(cxx-js cxx-mlir) +endif() + target_link_options(cxx-js PUBLIC "SHELL:-s ENVIRONMENT=web" "SHELL:-s MINIMAL_RUNTIME" diff --git a/src/js/cxx/api.cc b/src/js/cxx/api.cc index b012f035..8ee4cd5f 100644 --- a/src/js/cxx/api.cc +++ b/src/js/cxx/api.cc @@ -37,6 +37,13 @@ #include #include +#ifdef CXX_WITH_MLIR +#include +#include +#include +#include +#endif + using namespace emscripten; namespace { @@ -179,6 +186,31 @@ struct WrappedUnit { co_return val{true}; } + + auto emitIR() -> std::string { +#ifdef CXX_WITH_MLIR + mlir::MLIRContext context; + context.loadDialect(); + + cxx::Codegen codegen(context, unit.get()); + + auto ir = codegen(unit->ast()); + + mlir::OpPrintingFlags flags; + flags.enableDebugInfo(true, true); + + std::ostringstream out; + llvm::raw_os_ostream os(out); + ir.module->print(os, flags); + os.flush(); + + auto code = out.str(); + + return code; +#else + return {}; +#endif + } }; auto getTokenText(std::intptr_t handle, std::intptr_t unitHandle) @@ -381,7 +413,8 @@ EMSCRIPTEN_BINDINGS(cxx) { .function("parse", &WrappedUnit::parse) .function("getHandle", &WrappedUnit::getHandle) .function("getUnitHandle", &WrappedUnit::getUnitHandle) - .function("getDiagnostics", &WrappedUnit::getDiagnostics); + .function("getDiagnostics", &WrappedUnit::getDiagnostics) + .function("emitIR", &WrappedUnit::emitIR); function("createUnit", &createUnit, allow_raw_pointers()); function("getASTKind", &getASTKind); diff --git a/src/mlir/cxx/mlir/CMakeLists.txt b/src/mlir/cxx/mlir/CMakeLists.txt index 3799b945..4f159df8 100644 --- a/src/mlir/cxx/mlir/CMakeLists.txt +++ b/src/mlir/cxx/mlir/CMakeLists.txt @@ -20,6 +20,9 @@ target_link_libraries(cxx-mlir PUBLIC MLIRControlFlowDialect MLIRSCFDialect ) + +target_compile_definitions(cxx-mlir PUBLIC CXX_WITH_MLIR) + add_dependencies(cxx-mlir MLIRCxxOpsIncGen) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") diff --git a/templates/cxx-browser-esm-vite/src/main.ts b/templates/cxx-browser-esm-vite/src/main.ts index 393f223c..04cec687 100644 --- a/templates/cxx-browser-esm-vite/src/main.ts +++ b/templates/cxx-browser-esm-vite/src/main.ts @@ -44,12 +44,10 @@ async function main() { source, }); - parser.parse(); + const ast = await parser.parse(); const rows: string[] = []; - const ast = parser.getAST(); - for (const { node, depth } of ast?.walk().preVisit() ?? []) { if (!(node instanceof AST)) { continue; diff --git a/templates/cxx-parse-esm/index.js b/templates/cxx-parse-esm/index.js index e8ae4651..9d0a9d40 100644 --- a/templates/cxx-parse-esm/index.js +++ b/templates/cxx-parse-esm/index.js @@ -51,7 +51,7 @@ async function main() { const parser = new Parser({ source, path: "source.cc" }); - await parser.parse(); + const ast = await parser.parse(); const diagnostics = parser.getDiagnostics(); @@ -59,10 +59,8 @@ async function main() { console.log("diagnostics", diagnostics); } - const ast = parser.getAST(); - for (const { node, slot, depth } of ast?.walk().preVisit() ?? []) { - if (!node instanceof AST) continue; + if (!(node instanceof AST)) continue; const ind = " ".repeat(depth * 2); const kind = ASTKind[node.getKind()]; const member = slot !== undefined ? `${ASTSlot[slot]}: ` : ""; diff --git a/templates/cxx-parse/index.js b/templates/cxx-parse/index.js index 04eb3504..80ffec2a 100644 --- a/templates/cxx-parse/index.js +++ b/templates/cxx-parse/index.js @@ -59,7 +59,7 @@ async function main() { const ast = parser.getAST(); for (const { node, slot, depth } of ast?.walk().preVisit() ?? []) { - if (!node instanceof AST) continue; + if (!(node instanceof AST)) continue; const ind = " ".repeat(depth * 2); const kind = ASTKind[node.getKind()]; const member = slot !== undefined ? `${ASTSlot[slot]}: ` : "";