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
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include "kappa/dsl/ast.hpp"
#include "kappa/dsl/system.hpp"
#include <optional>
#include <unordered_map>
#include <string>
namespace kappa::config {
struct ResolvedPackage {
dsl::PackageDef original;
std::unordered_map<std::string, dsl::FeatureDef> features;
std::unordered_map<std::string, std::string> config;
};
ResolvedPackage resolve_package(
const dsl::PackageDef& pkg,
const dsl::SystemBlock& system,
const std::optional<dsl::PackageRef>& overrides);
std::unordered_map<std::string, std::string> resolve_config(
const dsl::PackageDef& pkg,
const dsl::SystemBlock& system,
const std::optional<dsl::PackageRef>& overrides);
} // namespace kappa::config
+8
View File
@@ -52,6 +52,13 @@ struct ServiceInit {
std::unordered_map<std::string, std::string> env;
};
struct Assertion {
std::string message;
std::string field;
std::string op; // "==" or "!="
std::string value;
};
struct PackageDef {
std::string name;
std::string version;
@@ -65,6 +72,7 @@ struct PackageDef {
std::vector<Patch> patches;
std::vector<EnvEntry> env_entries;
std::unordered_map<std::string, ServiceInit> service;
std::vector<Assertion> assertions;
std::unordered_set<std::string> const_keys;
Phase prepare;
Phase build;
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include <format>
#include <stdexcept>
#include <string>
namespace kappa::dsl {
class ParseError : public std::runtime_error {
public:
ParseError(int line, int col, const std::string& msg)
: std::runtime_error(std::format("{}:{}: {}", line, col, msg)) {}
};
inline int parse_int(int line, int col, const std::string& lexeme) {
try {
std::size_t pos = 0;
int val = std::stoi(lexeme, &pos);
if (pos != lexeme.size()) {
throw ParseError(line, col,
std::format("expected integer, got '{}'", lexeme));
}
return val;
} catch (const std::invalid_argument&) {
throw ParseError(line, col,
std::format("expected integer, got '{}'", lexeme));
} catch (const std::out_of_range&) {
throw ParseError(line, col,
std::format("integer out of range: '{}'", lexeme));
}
}
} // namespace kappa::dsl
+4
View File
@@ -34,6 +34,7 @@ struct BootBlock {
std::string init;
std::string efi;
std::string swap;
std::string root;
std::string bootloader;
std::unordered_map<std::string, std::string> params;
};
@@ -52,13 +53,16 @@ struct ServiceRef {
};
struct SystemConfig {
std::vector<std::string> imports;
SystemBlock system;
std::vector<PackageRef> packages;
std::vector<ServiceRef> services;
BootBlock boot;
std::vector<UserRef> users;
std::vector<Assertion> assertions;
};
SystemConfig parse_system_config(std::string_view source);
SystemConfig resolve_imports(const SystemConfig& cfg, const std::string& base_dir);
} // namespace kappa::dsl
+2
View File
@@ -35,6 +35,8 @@ enum class TokenType {
KwPatches,
KwEnv,
KwService,
KwAssert,
KwImport,
KwPrepare,
KwBuild,
KwCheck,
-23
View File
@@ -1,23 +0,0 @@
#pragma once
#include <iosfwd>
#include <string>
#include <vector>
namespace kappa {
struct PackageConfig {
std::string name;
std::string version;
std::string description;
std::string source_url;
std::string source_extension;
std::string source_hash;
std::vector<std::string> dependencies;
std::string build_system;
};
PackageConfig parse_package(const std::string& toml_path);
void print_package(std::ostream& os, const PackageConfig& pkg);
} // namespace kappa