Files
bux-lang/src_bux/cli.bux
T
dimgigov cb256397bd Phase 7.9: Self-hosted compiler buxc2 builds and runs! 🎉
buxc (Nim bootstrap) successfully compiles buxc2 (Bux self-hosted compiler)
into a working 88KB ELF x86-64 binary.

Compiler fixes (Nim):
- duplicate symbol: user funcs shadow stdlib funcs via mergeDecls()
- forward declarations: func without body + definition (both orderings)
- extern func dedup: same extern in multiple files
- discard keyword: new language keyword, lowered to expr stmt or no-op
- parser: keywords as field names + advance-on-error safeguard
- parser: var without initializer (zero-init)
- parser: multi-line || && continuation expressions
- parser: else-if chain newline handling
- C backend: const declarations emitted as #define
- C backend: load(field_ptr) → base.field optimization (fixes lvalue errors)

Source fixes (src_bux/*.bux):
- types.bux: tk* → ty* prefix for type kind constants (avoid token conflict)
- sema.bux: remaining tk* → ty* references, StringMap → *void workaround
- hir_lower.bux: ekReturn removed, Lcx_LowerParam helper, *f dereference
- c_backend.bux: &mod.funcs[i] for pointer passing
- cli.bux: ReadFile/WriteFile → bux_read_file/bux_write_file wrappers
- parser.bux: pathStr.len → String_Len(pathStr)
- types.bux: "*" + x → String_Concat("*", x)

Build system:
- Makefile: added 4 missing examples + selfhost target
- PLAN.md: updated with actual project state, Phase 7.9 marked complete

All 18 examples pass, all unit tests pass.
2026-05-31 16:34:36 +03:00

177 lines
4.9 KiB
Plaintext

// cli.bux — CLI driver for the Bux self-hosting compiler
// Wires together: Lexer → Parser → Sema → HirLower → CBackend
module Cli {
extern func PrintLine(s: String);
extern func Print(s: String);
extern func bux_read_file(path: String) -> String;
extern func bux_write_file(path: String, content: String) -> bool;
func ReadFile(path: String) -> String {
return bux_read_file(path);
}
func WriteFile(path: String, content: String) -> bool {
return bux_write_file(path, content);
}
// Import the compiler pipeline
// In self-hosting mode, these are compiled together from src_bux/
// ---------------------------------------------------------------------------
// Compile a single .bux source file
// ---------------------------------------------------------------------------
func Cli_Compile(source: String, sourceName: String) -> String {
// Phase 1: Lex
let lex: *Lexer = Lexer_Tokenize(source);
if Lexer_DiagCount(lex) > 0 {
PrintLine("Lex errors:");
var i: int = 0;
while i < Lexer_DiagCount(lex) {
Print(" ");
PrintLine(lex.diags[i].message);
i = i + 1;
}
return "";
}
// Phase 2: Parse
let mod: *Module = Parser_Parse(lex.tokens, lex.tokenCount);
if mod == null as *Module {
PrintLine("Parse failed");
return "";
}
// Phase 3: Semantic analysis
let sema: *Sema = Sema_Analyze(mod);
if Sema_HasError(sema) {
PrintLine("Sema errors:");
var i: int = 0;
while i < Sema_DiagCount(sema) {
Print(" ");
PrintLine(sema.diags[i].message);
i = i + 1;
}
return "";
}
// Phase 4: HIR lowering
let hirMod: *HirModule = HirLower_LowerModule(mod, sema);
if hirMod == null as *HirModule {
PrintLine("HIR lowering failed");
return "";
}
// Phase 5: C code generation
let cCode: String = CBackend_Generate(hirMod);
// Cleanup
Lexer_Free(lex);
Sema_Free(sema);
return cCode;
}
// ---------------------------------------------------------------------------
// Build command
// ---------------------------------------------------------------------------
func Cli_Build(srcPath: String, outPath: String) -> int {
let source: String = ReadFile(srcPath);
if String_Eq(source, "") || !FileExists(srcPath) {
Print("Error: cannot read source file: ");
PrintLine(srcPath);
return 1;
}
Print("Compiling ");
PrintLine(srcPath);
let cCode: String = Cli_Compile(source, srcPath);
if String_Eq(cCode, "") {
PrintLine("Compilation failed");
return 1;
}
// Write C output
let ok: bool = WriteFile(outPath, cCode);
if ok {
Print(" → C code written to ");
PrintLine(outPath);
return 0;
} else {
PrintLine("Error: cannot write output file");
return 1;
}
}
// ---------------------------------------------------------------------------
// Check command (compile only, no output)
// ---------------------------------------------------------------------------
func Cli_Check(srcPath: String) -> int {
let source: String = ReadFile(srcPath);
if String_Eq(source, "") {
PrintLine("Error: cannot read source file");
return 1;
}
let cCode: String = Cli_Compile(source, srcPath);
if String_Eq(cCode, "") {
return 1;
}
PrintLine("Check passed");
return 0;
}
// ---------------------------------------------------------------------------
// Main entry — dispatch based on args
// ---------------------------------------------------------------------------
func Cli_Run(args: *String, argCount: int) -> int {
if argCount < 2 {
PrintLine("Bux Self-Hosting Compiler v0.2.0");
PrintLine("Usage: buxc <command> [args]");
PrintLine("Commands: build, check, run, version");
PrintLine("");
PrintLine("Pipeline modules:");
PrintLine(" Lexer ✅ 695 lines");
PrintLine(" Parser ✅ 1004 lines");
PrintLine(" Sema ✅ 393 lines");
PrintLine(" HirLower ✅ 307 lines");
PrintLine(" CBackend ✅ 264 lines");
PrintLine(" Total: 3830 lines of Bux");
return 0;
}
let cmd: String = args[1];
if String_Eq(cmd, "version") {
PrintLine("Bux 0.2.0 (self-hosting bootstrap)");
return 0;
}
if String_Eq(cmd, "check") {
if argCount < 3 {
PrintLine("Usage: buxc check <file.bux>");
return 1;
}
return Cli_Check(args[2]);
}
if String_Eq(cmd, "build") {
let src: String = "src/Main.bux";
let out: String = "build/main.c";
if argCount >= 3 { src = args[2]; }
if argCount >= 4 { out = args[3]; }
return Cli_Build(src, out);
}
Print("Unknown command: ");
PrintLine(cmd);
return 1;
}
}