fix: review fixes + feat: imports, assertions, merge engine, per-package overrides

Review fixes (8 blocking issues):
- Extract ParseError to shared error.hpp (ODR fix)
- Remove dead package.cpp/package.hpp + tomlplusplus dep
- Safe parse_int() helper replacing crash-prone std::stoi
- consume_string() now accepts bare numbers and idents
- line_at() fixed for post-EOF line numbers
- Subcommand validation before file read in CLI
- KwService/KwAssert/KwImport added to consume_ident()
- root partition promoted to first-class BootBlock field

New features:
- Imports: imports = [...] with recursive merge resolution
- Assertions: assert { "msg" : field op value } in both parsers
- Merge engine: resolve_package() with features/config merge + force support
- Per-package overrides: /kappa/system/builds/<name>.kap
- .gitignore: added vcpkg_installed/ and kappa binary
This commit is contained in:
2026-07-29 23:52:03 -04:00
parent d5f7d397ed
commit 0c1e82d66b
18 changed files with 325 additions and 212 deletions
+22 -13
View File
@@ -48,24 +48,25 @@ static std::string read_file(const char* path) {
static void handle_parse_error(const char* path,
std::string_view source,
const std::runtime_error& e) {
// ParseError format: "line:col: message"
auto msg = std::string_view(e.what());
auto first_colon = msg.find(':');
auto second_colon = msg.find(':', first_colon + 1);
if (first_colon != std::string_view::npos &&
second_colon != std::string_view::npos) {
int line = std::stoi(std::string(msg.substr(0, first_colon)));
int col = std::stoi(std::string(
msg.substr(first_colon + 1, second_colon - first_colon - 1)));
auto message = msg.substr(second_colon + 2); // skip ": "
try {
int line = std::stoi(std::string(msg.substr(0, first_colon)));
int col = std::stoi(std::string(
msg.substr(first_colon + 1, second_colon - first_colon - 1)));
auto message = msg.substr(second_colon + 2);
cli::print_error(std::cerr, source,
{path, line, col}, message,
"check the syntax at this location");
} else {
std::cerr << "error: " << e.what() << '\n';
cli::print_error(std::cerr, source,
{path, line, col}, message,
"check the syntax at this location");
return;
} catch (const std::exception&) {}
}
std::cerr << "error: " << e.what() << '\n';
}
int main(int argc, char* argv[]) {
@@ -86,6 +87,16 @@ int main(int argc, char* argv[]) {
return 0;
}
bool valid_subcommand = (subcommand == "parse-package")
|| (subcommand == "parse-config")
|| (subcommand == "validate");
if (!valid_subcommand) {
std::cerr << "error: unknown subcommand '" << subcommand << "'\n\n";
print_usage();
return 1;
}
// Find the file argument (skip flags)
const char* file_arg = nullptr;
for (int i = 2; i < argc; ++i) {
@@ -145,7 +156,5 @@ int main(int argc, char* argv[]) {
}
}
std::cerr << "error: unknown subcommand '" << subcommand << "'\n\n";
print_usage();
return 1;
return 1; // unreachable
}