Frontends
MPL Compiler Frontends — Overview
MPL Compiler Frontends — Overview
MPL_Compiler ships 9 first-class language frontends that share a single
target: a unified EMPL IR (Extended Multi-Platform Language Intermediate
Representation) defined in core/ir/EMPLNode.h. From that IR the only
currently-shipped backend (backends/cpp/) lowers the program to C++20.
| Source language | Frontend file | File extensions | Document |
|---|---|---|---|
| JavaScript / TypeScript | frontends/javascript/JSFrontend.h |
.js .mjs .cjs .ts .tsx .mts .cts .jsx |
javascript.md |
| Python | frontends/python/PythonFrontend.h |
.py |
python.md |
| C# | frontends/csharp/CSharpFrontend.h |
.cs |
csharp.md |
| Go | frontends/go/GoFrontend.h |
.go |
go.md |
| Rust | frontends/rust/RustFrontend.h |
.rs |
rust.md |
| PHP | frontends/php/PHPFrontend.h |
.php |
php.md |
| Ruby | frontends/ruby/RubyFrontend.h |
.rb |
ruby.md |
| Java | frontends/java/JavaFrontend.h |
.java |
java.md |
| EMPLS (built-in) | frontends/empls/EMPLSFrontend.h |
.empls |
empls.md |
Two additional frontends exist (Swift, Kotlin) but are not covered here.
Architectural map
┌──────────────────────────────────────────────────────┐
│ ILanguageFrontend (interface) │
│ core/plugin/ILanguageFrontend.h:15 │
├──────────────────────────────────────────────────────┤
│ languageName() │
│ fileExtensions() │
│ parse(source, filename) -> ModuleNode │
└──────────────────────────────────────────────────────┘
▲ ▲
┌───────────────────────┘ └───────────────────────────┐
│ │
┌───────┴───────────┐ ┌────────────┴─────────────┐
│ FrontendBase │ │ BraceFrontendBase │
│ core/plugin/ │ │ core/plugin/ │
│ FrontendBase.h │ │ BraceFrontendBase.h │
│ (line-based, │ │ (brace-delimited langs: │
│ simple print + │ │ JS, C#, Go, Rust, PHP, │
│ var declarations)│ │ Java, EMPLS, …) │
└───────────────────┘ └──────────────────────────┘
PluginRegistry (core/plugin/PluginRegistry.h:12) is a process-wide
singleton that holds an unordered map of language-name → frontend and an
extension → language-name map. The CLI uses it to dispatch by file extension
or by explicit --target argument.
Quick start: how a source file becomes C++
- CLI dispatch (
MPL_Compiler.cpp:32-47):registerPlugins()registers nine frontend instances and one backend (CppBackend). The CLI then readsargv[1], finds the matching frontend viaPluginRegistry::getFrontend(extension lookup), and callsfrontend->parse(source, filename). - Frontend parsing: each frontend is a
BraceFrontendBasesubclass (orFrontendBasefor line-oriented languages like Python and Ruby). It produces anir::ModuleNode. - EMPL IR: every frontend yields the same node types:
ModuleNode,FunctionDeclNode,ClassDeclNode,InterfaceDeclNode,EnumDeclNode,VariableDeclNode,BlockNode,IfNode,ForNode,ForEachNode,WhileNode,SwitchNode,TryCatchNode,BinaryOpNode,UnaryOpNode,TernaryNode,FunctionCallNode,MethodCallNode,MemberAccessNode,IndexAccessNode,LiteralNode,LambdaNode,AwaitNode,YieldNode,ImportNode,ExportNode,AssignmentNode,BreakNode,ContinueNode,ReturnNode,StandardLibraryCallNode,UnsupportedNode,DestructuringPatternNode,InterfaceDeclNode,TypeAliasDeclNode, and a few more. - C++ backend:
backends/cpp/CppBackend.hwalks the IR and emits C++ that links againstMPL_Standard/System/empl.h(and the language-specific runtime underfrontends/<lang>/runtime/for JavaScript).
The IR is language-neutral
core/ir/EMPLNode.h is the contract every frontend and every backend shares.
Critical language-neutral rules enforced by all frontends:
| Rule | Source line convention |
|---|---|
metadata keys MUST be language-neutral |
decl_origin, async, generator, using_decl, using_await, exported, export_name, global_using, static_using, etc. — never js_*, csharp_*, etc. |
decl_origin values |
var, let, const, :=, pub, final, require, import, import_eq, using, etc. |
| Standard library calls | One node: StandardLibraryCallNode(moduleName, functionName, args) with moduleName from {Console, Math, String, IO, Process, Environment, DateTime, Json, Convert, Collection, …}. |
| Brace-only languages | Inherit BraceFrontendBase. The base owns parseBlock, parseStatement, expression parsing, and print patterns. |
| Indentation-only languages | Inherit FrontendBase or implement the parse() entry directly (Python and Ruby both do the latter, building their own indent-stack scope tracker). |
See architecture.md for the full lex/parse/IR pipeline.
Standard library — single source of truth
All language-specific standard library mapping tables live in
frontends/<lang>/<Lang>StdLib.h / .cpp. They each map the source
language's qualified name (e.g. console.log, math.sqrt,
fmt.Println, println!) to a language-neutral MPL module+function
(e.g. Console.WriteLine, Math.Sqrt). The canonical spec lives at
MPL_Standard/Specification.json; the C++ implementations are in
MPL_Standard/System/CppImpl.h.
| File | Mappings |
|---|---|
JsStdLib.cpp |
console.log/info/warn/error/debug, Math.*, process.exit/cwd, JSON.stringify/parse |
PythonStdLib.h |
print, input, len, abs, round, min, max, int, float, str, math.sqrt/floor/ceil/pow/log/sin/cos/tan, os.path.*, sys.exit, json.loads/dumps |
CSharpStdLib.cpp |
Two large tables: typeMap (~570 entries, Console → System.Console, etc.) and methodMap (~470 entries) |
GoStdLib.h |
fmt.Println/Printf/Print/Sprintf, math., os., strings.* |
RustStdLib.h |
println!/print!/eprintln!/eprint!, std::process::exit, std::env::var, std::env::current_dir, std::fs::read_to_string, std::fs::write |
PhpStdLib.h |
echo, print, var_dump, print_r, abs, floor, ceil, round, sqrt, pow, max, min, log, sin, cos, rand, strlen, strtolower, strtoupper, trim, explode, str_starts_with, str_ends_with, exit, die, getenv, json_encode, json_decode, file_get_contents, file_put_contents, file_exists |
RubyStdLib.h |
puts, print, p, gets, exit, abort, rand |
JavaStdLib.h |
System.out.println/print, System.err.println/print, Math.*, System.exit/getenv/getProperty, Integer.parseInt, Double.parseDouble, String.valueOf |
EMPLS does not own a StdLib table — it routes through the shared brace-level
print-pattern handling in BraceFrontendBase.
File layout
frontends/
├── javascript/ — JSFrontend.h + Lexer/Parser + 5 runtime headers (~32 K LOC)
├── python/ — PythonFrontend.h + PythonStdLib.h (header-only Python header)
├── csharp/ — CSharpFrontend.cpp + Lexer/Parser/Converter/Sema + StdLib
├── go/ — GoFrontend.h + Lexer/Parser + GoStdLib
├── rust/ — RustFrontend.h (single header with brace language transforms)
├── php/ — PHPFrontend.h (single header with many static transforms)
├── ruby/ — RubyFrontend.h (single header, line-based parser)
├── java/ — JavaFrontend.h (single header with many static transforms)
├── empls/ — EMPLSFrontend.h (single header; brace-based)
└── (swift, kotlin) — not documented here
Plugin registration (pointers)
// MPL_Compiler.cpp:32-47
void registerPlugins() {
auto& reg = plugin::PluginRegistry::instance();
reg.registerFrontend(std::make_unique<frontends::JSFrontend>());
reg.registerFrontend(std::make_unique<frontends::PythonFrontend>());
reg.registerFrontend(std::make_unique<frontends::CSharpFrontend>());
reg.registerFrontend(std::make_unique<frontends::GoFrontend>());
reg.registerFrontend(std::make_unique<frontends::RustFrontend>());
reg.registerFrontend(std::make_unique<frontends::PHPFrontend>());
reg.registerFrontend(std::make_unique<frontends::RubyFrontend>());
reg.registerFrontend(std::make_unique<frontends::JavaFrontend>());
reg.registerFrontend(std::make_unique<frontends::EMPLSFrontend>());
reg.registerBackend(std::make_unique<backends::CppBackend>());
}
See registration.md for the full registration mechanism and how to add a 10th language.
Per-language docs
- javascript.md — ES2025/Node 26/TS 6 features, JSX, npm packages
- python.md — Decorators, comprehensions, walrus, match
- csharp.md — Records, init setter, field keyword, LINQ
- go.md — Channels, select, go/defer, for-range, composite literals
- rust.md — Traits, lifetimes, let-else, if-let chains, gen blocks
- php.md — Named args, match, attributes, enums, fibers, readonly classes
- ruby.md — String interpolation, blocks, modules, refinements
- java.md — Text blocks, records, sealed, pattern matching, virtual threads
- empls.md — var::, func::, class, struct, range, pipeline
|>
Also see:
- architecture.md — Lexer/Parser/IR pipeline internals
- registration.md —
PluginRegistry,registerPlugins(), custom languages - limitations.md — Known gaps per frontend
Cross-references
core/ir/EMPLNode.h— the IR contract (see alsoEMPLPrinter.h,EMPLValidator.h,EMPLCanonicalizer.h)core/plugin/ILanguageFrontend.h— the contract every frontend obeyscore/plugin/PluginRegistry.h— the registryMPL_Compiler.cpp:32—registerPlugins()MPL_Standard/Specification.json— canonical language-neutral stdlib specMPL_Standard/System/empl.h— language-neutral runtime umbrella header