dol 0.8.1

DOL (Design Ontology Language) - A declarative specification language for ontology-first development
// Effect System Test: Messaging Effects
// ======================================
//
// What this test validates:
//   - Functions performing message passing are inferred as effectful
//   - send, recv, pending, broadcast operations mark functions as effectful
//   - Messaging effect is distinct from IO effect
//
// Expected effect inference results:
//   - send(target, msg) -> Effectful(Msg)
//   - recv() -> Effectful(Msg)
//   - pending() -> Effectful(Msg)
//   - broadcast(msg) -> Effectful(Msg)
//   - request(target, msg) -> Effectful(Msg)
//   - reply(msg) -> Effectful(Msg)

gene Msg.Basic @0.1.0 {
    """
    Basic messaging operations for actor-like communication.
    These operations interact with the message queue and
    other actors, introducing the Msg effect.
    """

    // Effectful(Msg): send message to target actor
    fn send(target: ActorId, msg: Any) -> Unit {
        @msg.send(target, msg)
    }

    // Effectful(Msg): receive next message (blocking)
    fn recv() -> Any {
        @msg.recv()
    }

    // Effectful(Msg): check if messages are pending
    fn pending() -> Bool {
        @msg.pending()
    }

    // Effectful(Msg): receive with timeout
    fn recv_timeout(timeout_ms: Int) -> Option[Any] {
        @msg.recv_timeout(timeout_ms)
    }

    // Effectful(Msg): try to receive (non-blocking)
    fn try_recv() -> Option[Any] {
        @msg.try_recv()
    }

    // Effectful(Msg): broadcast to all known actors
    fn broadcast(msg: Any) -> Unit {
        @msg.broadcast(msg)
    }

    // Effectful(Msg): get own actor ID
    fn self_id() -> ActorId {
        @msg.self()
    }
}

gene Msg.Patterns @0.1.0 {
    """
    Common messaging patterns built on basic operations.
    All inherit the Msg effect from underlying calls.
    """

    // Effectful(Msg): request-response pattern
    fn request(target: ActorId, msg: Any) -> Any {
        let request_id = @msg.new_request_id();
        @msg.send(target, { type: "request", id: request_id, payload: msg });
        loop {
            let response = @msg.recv();
            if response.type == "response" && response.id == request_id {
                return response.payload
            }
            // Re-queue other messages
            @msg.requeue(response)
        }
    }

    // Effectful(Msg): reply to current request
    fn reply(request_id: RequestId, msg: Any) -> Unit {
        let sender = @msg.current_sender();
        @msg.send(sender, { type: "response", id: request_id, payload: msg })
    }

    // Effectful(Msg): forward message to another actor
    fn forward(target: ActorId, msg: Any) -> Unit {
        @msg.send(target, msg)
    }

    // Effectful(Msg): subscribe to topic
    fn subscribe(topic: String) -> Unit {
        @msg.subscribe(topic)
    }

    // Effectful(Msg): publish to topic
    fn publish(topic: String, msg: Any) -> Unit {
        @msg.publish(topic, msg)
    }

    // Effectful(Msg): spawn new actor
    fn spawn(gene: Gene) -> ActorId {
        @msg.spawn(gene)
    }

    // Effectful(Msg): link to actor (receive exit signals)
    fn link(target: ActorId) -> Unit {
        @msg.link(target)
    }
}

gene Msg.Selective @0.1.0 {
    """
    Selective receive patterns for filtering messages.
    """

    // Effectful(Msg): receive message matching predicate
    fn recv_matching(predicate: Fn(Any) -> Bool) -> Any {
        loop {
            let msg = @msg.recv();
            if predicate(msg) {
                return msg
            }
            @msg.requeue(msg)
        }
    }

    // Effectful(Msg): receive message of specific type
    fn recv_type(msg_type: String) -> Any {
        recv_matching(|msg| msg.type == msg_type)
    }

    // Effectful(Msg): receive from specific sender
    fn recv_from(sender: ActorId) -> Any {
        recv_matching(|msg| @msg.sender_of(msg) == sender)
    }
}

// Test assertions for effect inference
test effects {
    assert_effectful(Msg.Basic.send, Msg);
    assert_effectful(Msg.Basic.recv, Msg);
    assert_effectful(Msg.Basic.pending, Msg);
    assert_effectful(Msg.Basic.recv_timeout, Msg);
    assert_effectful(Msg.Basic.try_recv, Msg);
    assert_effectful(Msg.Basic.broadcast, Msg);
    assert_effectful(Msg.Basic.self_id, Msg);

    assert_effectful(Msg.Patterns.request, Msg);
    assert_effectful(Msg.Patterns.reply, Msg);
    assert_effectful(Msg.Patterns.forward, Msg);
    assert_effectful(Msg.Patterns.subscribe, Msg);
    assert_effectful(Msg.Patterns.publish, Msg);
    assert_effectful(Msg.Patterns.spawn, Msg);
    assert_effectful(Msg.Patterns.link, Msg);

    assert_effectful(Msg.Selective.recv_matching, Msg);
    assert_effectful(Msg.Selective.recv_type, Msg);
    assert_effectful(Msg.Selective.recv_from, Msg);
}