irc: add serialization support for patterns and string interpolation

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I244ae722016b5b49915e23522a1fb72e6a6a6964
This commit is contained in:
raf 2026-04-24 14:40:02 +03:00
commit 584d84542e
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF

View file

@ -74,6 +74,10 @@ struct Serializer::Impl {
return NodeType::LETREC;
if (node.holds<AssertNode>())
return NodeType::ASSERT;
if (node.holds<LambdaPatternNode>())
return NodeType::LAMBDA_PATTERN;
if (node.holds<StringInterpolationNode>())
return NodeType::STRING_INTERPOLATION;
return NodeType::ERROR;
}
@ -199,6 +203,53 @@ struct Serializer::Impl {
write_node(*n->cond);
if (n->body)
write_node(*n->body);
} else if (auto* n = node.get_if<LambdaPatternNode>()) {
// Required fields
write_u32(n->required_fields.size());
for (const auto& field : n->required_fields) {
write_string(field.name);
write_u8(0); // No default
}
// Optional fields
write_u32(n->optional_fields.size());
for (const auto& field : n->optional_fields) {
write_string(field.name);
if (field.default_value && *field.default_value) {
write_u8(1);
write_node(**field.default_value);
} else {
write_u8(0);
}
}
// At-binding
if (n->at_binding) {
write_u8(1);
write_string(*n->at_binding);
} else {
write_u8(0);
}
// Allow extra
write_u8(n->allow_extra ? 1 : 0);
// Body
if (n->body)
write_node(*n->body);
} else if (auto* n = node.get_if<StringInterpolationNode>()) {
write_u32(n->parts.size());
for (const auto& part : n->parts) {
write_u8(static_cast<uint8_t>(part.type));
if (part.type == StringPart::Type::LITERAL) {
write_string(part.literal);
} else { // EXPR
if (part.expr)
write_node(*part.expr);
}
}
}
}
};
@ -430,6 +481,72 @@ struct Deserializer::Impl {
auto body = read_node();
return std::make_shared<Node>(AssertNode(cond, body, line));
}
case NodeType::LAMBDA_PATTERN: {
// Read required fields
uint32_t num_required = read_u32();
std::vector<PatternField> required_fields;
required_fields.reserve(num_required);
for (uint32_t i = 0; i < num_required; i++) {
std::string name = read_string();
read_u8(); // Discard has_default (always 0)
required_fields.emplace_back(name, std::nullopt);
}
// Read optional fields
uint32_t num_optional = read_u32();
std::vector<PatternField> optional_fields;
optional_fields.reserve(num_optional);
for (uint32_t i = 0; i < num_optional; i++) {
std::string name = read_string();
uint8_t has_default = read_u8();
std::optional<std::shared_ptr<Node>> default_val;
if (has_default) {
default_val = read_node();
}
optional_fields.emplace_back(name, default_val);
}
// Read at-binding
std::optional<std::string> at_binding;
if (read_u8()) {
at_binding = read_string();
}
// Read allow_extra
bool allow_extra = read_u8() != 0;
// Read body
auto body = read_node();
// Construct node
LambdaPatternNode lambda_pattern(body, line);
lambda_pattern.required_fields = std::move(required_fields);
lambda_pattern.optional_fields = std::move(optional_fields);
lambda_pattern.at_binding = at_binding;
lambda_pattern.allow_extra = allow_extra;
return std::make_shared<Node>(std::move(lambda_pattern));
}
case NodeType::STRING_INTERPOLATION: {
uint32_t num_parts = read_u32();
std::vector<StringPart> parts;
parts.reserve(num_parts);
for (uint32_t i = 0; i < num_parts; i++) {
uint8_t type_byte = read_u8();
StringPart::Type type = static_cast<StringPart::Type>(type_byte);
if (type == StringPart::Type::LITERAL) {
std::string literal = read_string();
parts.push_back(StringPart::make_literal(std::move(literal)));
} else { // EXPR
auto expr = read_node();
parts.push_back(StringPart::make_expr(expr));
}
}
return std::make_shared<Node>(StringInterpolationNode(std::move(parts), line));
}
default:
throw std::runtime_error("Unknown node type in IR");
}