diff --git a/src/irc/serializer.cpp b/src/irc/serializer.cpp index 73051a7..23cd392 100644 --- a/src/irc/serializer.cpp +++ b/src/irc/serializer.cpp @@ -74,6 +74,10 @@ struct Serializer::Impl { return NodeType::LETREC; if (node.holds()) return NodeType::ASSERT; + if (node.holds()) + return NodeType::LAMBDA_PATTERN; + if (node.holds()) + 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()) { + // 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()) { + write_u32(n->parts.size()); + + for (const auto& part : n->parts) { + write_u8(static_cast(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(AssertNode(cond, body, line)); } + case NodeType::LAMBDA_PATTERN: { + // Read required fields + uint32_t num_required = read_u32(); + std::vector 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 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> default_val; + if (has_default) { + default_val = read_node(); + } + optional_fields.emplace_back(name, default_val); + } + + // Read at-binding + std::optional 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(std::move(lambda_pattern)); + } + case NodeType::STRING_INTERPOLATION: { + uint32_t num_parts = read_u32(); + std::vector 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(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(StringInterpolationNode(std::move(parts), line)); + } default: throw std::runtime_error("Unknown node type in IR"); }