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:
+42
-9
@@ -1,4 +1,5 @@
|
||||
#include "kappa/dsl/parser.hpp"
|
||||
#include "kappa/dsl/error.hpp"
|
||||
#include "kappa/dsl/lexer.hpp"
|
||||
|
||||
#include <format>
|
||||
@@ -8,12 +9,6 @@
|
||||
|
||||
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)) {}
|
||||
};
|
||||
|
||||
class Parser {
|
||||
public:
|
||||
explicit Parser(std::string_view source) : lexer_(source) { advance(); }
|
||||
@@ -215,7 +210,7 @@ void Parser::parse_body(PackageDef& pkg) {
|
||||
skip_newlines();
|
||||
while (!at(TokenType::Rbrace) && !at(TokenType::Eof)) {
|
||||
if (at(TokenType::Newline)) { advance(); continue; }
|
||||
auto init_name = current_.lexeme; // e.g. "runit", "s6"
|
||||
auto init_name = current_.lexeme;
|
||||
advance();
|
||||
consume(TokenType::Lbrace);
|
||||
skip_newlines();
|
||||
@@ -236,7 +231,8 @@ void Parser::parse_body(PackageDef& pkg) {
|
||||
skip_newlines();
|
||||
while (!at(TokenType::Rbracket) && !at(TokenType::Eof)) {
|
||||
si.ports.push_back(
|
||||
std::stoi(std::string(current_.lexeme)));
|
||||
parse_int(current_.line, current_.col,
|
||||
current_.lexeme));
|
||||
advance();
|
||||
skip_newlines();
|
||||
if (at(TokenType::Comma)) { consume(TokenType::Comma); }
|
||||
@@ -255,6 +251,42 @@ void Parser::parse_body(PackageDef& pkg) {
|
||||
consume(TokenType::Rbrace);
|
||||
break;
|
||||
|
||||
case TokenType::KwAssert:
|
||||
consume(TokenType::KwAssert);
|
||||
consume(TokenType::Lbrace);
|
||||
skip_newlines();
|
||||
while (!at(TokenType::Rbrace) && !at(TokenType::Eof)) {
|
||||
if (at(TokenType::Newline)) { advance(); continue; }
|
||||
Assertion a;
|
||||
a.message = consume(TokenType::String).lexeme;
|
||||
consume(TokenType::Ident); // ":"
|
||||
a.field = current_.lexeme;
|
||||
advance();
|
||||
if (at(TokenType::Equals)) {
|
||||
advance();
|
||||
if (at(TokenType::Equals)) {
|
||||
a.op = "=="; advance();
|
||||
} else {
|
||||
a.op = "=";
|
||||
}
|
||||
} else {
|
||||
a.op = current_.lexeme; advance();
|
||||
}
|
||||
if (at(TokenType::String)) {
|
||||
a.value = consume(TokenType::String).lexeme;
|
||||
} else if (at(TokenType::KwTrue)) {
|
||||
a.value = "true"; advance();
|
||||
} else if (at(TokenType::KwFalse)) {
|
||||
a.value = "false"; advance();
|
||||
} else {
|
||||
a.value = current_.lexeme; advance();
|
||||
}
|
||||
pkg.assertions.push_back(std::move(a));
|
||||
skip_newlines();
|
||||
}
|
||||
consume(TokenType::Rbrace);
|
||||
break;
|
||||
|
||||
case TokenType::KwPrepare:
|
||||
consume(TokenType::KwPrepare);
|
||||
pkg.prepare = parse_phase();
|
||||
@@ -420,7 +452,8 @@ Patch Parser::parse_patch_item() {
|
||||
} else if (key == "sha256") {
|
||||
p.sha256 = consume(TokenType::String).lexeme;
|
||||
} else if (key == "level") {
|
||||
p.level = std::stoi(std::string(current_.lexeme));
|
||||
p.level = parse_int(current_.line, current_.col,
|
||||
current_.lexeme);
|
||||
advance();
|
||||
}
|
||||
skip_newlines();
|
||||
|
||||
Reference in New Issue
Block a user