feat: system config DSL, services, CLI with rustc diagnostics

- System config parser (system/packages/services/boot/users blocks)
- Boot block: kernel, init, efi, swap, bootloader, root partition
- System-wide features, rollback config, swap partition
- Service block: per-init variants (runit, s6, etc.), system init selection via boot.init
- Feature-gated dependencies, config values accept numbers/bools/strings
- CLI: parse-package, parse-config, validate subcommands
- Rustc-style error diagnostics with source context, carets, help text
- Diagnostic module with ANSI color output
This commit is contained in:
2026-07-29 22:50:39 -04:00
parent a8b53681fc
commit d5f7d397ed
12 changed files with 850 additions and 19 deletions
+46
View File
@@ -209,6 +209,52 @@ void Parser::parse_body(PackageDef& pkg) {
consume(TokenType::Rbrace);
break;
case TokenType::KwService:
consume(TokenType::KwService);
consume(TokenType::Lbrace);
skip_newlines();
while (!at(TokenType::Rbrace) && !at(TokenType::Eof)) {
if (at(TokenType::Newline)) { advance(); continue; }
auto init_name = current_.lexeme; // e.g. "runit", "s6"
advance();
consume(TokenType::Lbrace);
skip_newlines();
ServiceInit si;
while (!at(TokenType::Rbrace) && !at(TokenType::Eof)) {
if (at(TokenType::Newline)) { advance(); continue; }
auto key = current_.lexeme;
advance();
consume(TokenType::Equals);
if (key == "exec") {
si.exec = consume(TokenType::String).lexeme;
} else if (key == "type") {
si.type = consume(TokenType::String).lexeme;
} else if (key == "user") {
si.user = consume(TokenType::String).lexeme;
} else if (key == "ports") {
consume(TokenType::Lbracket);
skip_newlines();
while (!at(TokenType::Rbracket) && !at(TokenType::Eof)) {
si.ports.push_back(
std::stoi(std::string(current_.lexeme)));
advance();
skip_newlines();
if (at(TokenType::Comma)) { consume(TokenType::Comma); }
skip_newlines();
}
consume(TokenType::Rbracket);
} else {
si.env[key] = consume(TokenType::String).lexeme;
}
skip_newlines();
}
consume(TokenType::Rbrace);
pkg.service[std::string(init_name)] = std::move(si);
skip_newlines();
}
consume(TokenType::Rbrace);
break;
case TokenType::KwPrepare:
consume(TokenType::KwPrepare);
pkg.prepare = parse_phase();