Parcourir la source

Modified the protocol syntax.

Matthew Carr il y a 1 an
Parent
commit
0461b8d0e6

+ 1 - 1
crates/btfs/src/lib.rs

@@ -13,7 +13,7 @@ impl CallMsg for Open {
     type Reply = ActorName;
 }
 protocol! {
-    let name = FsProtocol;
+    named FsProtocol;
     let states = [
         ServerInit, Listening,
         Client,

+ 2 - 2
crates/btproto/src/generation.rs

@@ -20,7 +20,7 @@ impl Protocol {
         for transition in self.transitions.iter() {
             // We only need to insert received messages because every sent message has a
             // corresponding receiver thanks to the validator.
-            if let Some(msg) = &transition.in_msg {
+            if let Some(msg) = transition.in_msg() {
                 msgs.insert(msg);
             }
         }
@@ -82,7 +82,7 @@ impl Message {
 impl Transition {
     /// Generates the tokens for the code which implements this transition.
     fn generate_tokens(&self) -> TokenStream {
-        let (msg_arg, method_ident) = if let Some(msg) = &self.in_msg {
+        let (msg_arg, method_ident) = if let Some(msg) = self.in_msg() {
             let msg_type = if msg.msg_type == Activate::ident() {
                 quote! { ::btrun::Activate }
             } else {

+ 6 - 5
crates/btproto/src/lib.rs

@@ -34,13 +34,14 @@ macro_rules! unwrap_or_compile_err {
 ///
 /// ## Grammar
 /// The grammar recognized by this macro is given below in the dialect of Extended Backus-Naur Form
-/// recognized by the `llgen` tool. The terminal symbol `Ident` has the same meaning as it does in
-/// the regular Rust syntax.
+/// recognized by the `llgen` tool. The terminal symbols `Ident` and `LitInt` have the same meaning
+/// as they do in the [syn] crate.
 ///
 /// ```ebnf
-/// protocol : name_def states_def ( transition ';' )* ;
-/// name_def : "let" "name" '=' Ident ';' ;
-/// states_def : "let" "states" '=' ident_array ';' ;
+/// protocol : name_def ';' ( version_def ';')? ( actor_def ';' )+ ( transition ';' )+ ;
+/// name_def : "named" Ident ;
+/// version_def: "version" LitInt;
+/// actor_def : "let" Ident '=' ident_array ;
 /// ident_array : '[' Ident ( ',' Ident )* ','? ']' ;
 /// transition : state ( '?' message )?  "->" states_list ( '>' dest_list )? ;
 /// state : Ident ident_array? ;

+ 272 - 106
crates/btproto/src/parsing.rs

@@ -3,169 +3,253 @@
 use proc_macro2::Span;
 use quote::format_ident;
 use syn::{
-    bracketed, parenthesized, parse::Parse, punctuated::Punctuated, spanned::Spanned, token, Ident,
-    Token,
+    bracketed, parenthesized, parse::Parse, punctuated::Punctuated, spanned::Spanned,
+    token::Bracket, Ident, LitInt, Token,
 };
 
 /// This type represents the top-level production for the protocol grammar.
 #[cfg_attr(test, derive(Debug, PartialEq))]
 pub(crate) struct Protocol {
     pub(crate) name_def: NameDef,
-    pub(crate) states_def: StatesDef,
+    name_def_semi: Token![;],
+    #[allow(dead_code)]
+    version_def: Option<(VersionDef, Token![;])>,
+    pub(crate) states_def: ActorDef,
+    states_def_semi: Token![;],
     pub(crate) transitions: Punctuated<Transition, Token![;]>,
 }
 
-impl Parse for Protocol {
-    /// protocol : name_def states_def ( transition ';' )* ;
-    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
-        Ok(Protocol {
-            name_def: input.parse()?,
-            states_def: input.parse()?,
-            transitions: input.parse_terminated(Transition::parse, Token![;])?,
-        })
-    }
-}
-
 #[cfg(test)]
 impl Protocol {
     pub(crate) fn new(
         name_def: NameDef,
-        states_def: StatesDef,
+        states_def: ActorDef,
         transitions: impl IntoIterator<Item = Transition>,
     ) -> Self {
         let mut transitions: Punctuated<Transition, Token![;]> = transitions.into_iter().collect();
         transitions.push_punct(Token![;](Span::call_site()));
         Self {
             name_def,
+            name_def_semi: Token![;](Span::call_site()),
+            version_def: None,
             states_def,
+            states_def_semi: Token![;](Span::call_site()),
             transitions,
         }
     }
+
+    pub(crate) fn with_version(
+        name_def: NameDef,
+        version_def: VersionDef,
+        states_def: ActorDef,
+        transitions: impl IntoIterator<Item = Transition>,
+    ) -> Self {
+        let mut protocol = Self::new(name_def, states_def, transitions);
+        protocol.version_def = Some((version_def, Token![;](Span::call_site())));
+        protocol
+    }
+}
+
+impl Parse for Protocol {
+    /// protocol : name_def ';' ( version_def ';')? ( actor_def ';' )+ ( transition ';' )+ ;
+    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+        let name_def = input.parse()?;
+        let name_def_semi = input.parse()?;
+        let version_def = if let Some((ident, _)) = input.cursor().ident() {
+            if ident == VersionDef::VERSION_IDENT {
+                Some((input.parse::<VersionDef>()?, input.parse::<Token![;]>()?))
+            } else {
+                None
+            }
+        } else {
+            None
+        };
+        let states_def = input.parse()?;
+        let states_def_semi = input.parse()?;
+        let transitions = input.parse_terminated(Transition::parse, Token![;])?;
+        Ok(Protocol {
+            name_def,
+            name_def_semi,
+            version_def,
+            states_def,
+            states_def_semi,
+            transitions,
+        })
+    }
 }
 
 impl GetSpan for Protocol {
     fn span(&self) -> Span {
         self.name_def
             .span()
+            .left_join(self.name_def_semi.span())
             .left_join(&self.states_def)
+            .left_join(self.states_def_semi.span())
             .left_join(punctuated_span(&self.transitions))
     }
 }
 
 #[cfg_attr(test, derive(Debug, PartialEq))]
 pub(crate) struct NameDef {
-    let_token: Token![let],
-    name_ident: Ident,
-    eq_token: Token![=],
+    named_ident: Ident,
     pub(crate) name: Ident,
-    semi_token: Token![;],
 }
 
 impl NameDef {
-    const NAME_IDENT: &str = "name";
-    const NAME_IDENT_ERR: &str = "invalid name declaration identifier";
+    const NAME_IDENT: &str = "named";
+    const NAME_IDENT_ERR: &str = "Invalid name declaration. Expected 'named'.";
 }
 
 #[cfg(test)]
 impl NameDef {
     pub(crate) fn new(name: &str) -> Self {
         Self {
-            let_token: Token![let](Span::call_site()),
-            name_ident: new_ident("name"),
-            eq_token: Token![=](Span::call_site()),
+            named_ident: new_ident(Self::NAME_IDENT),
             name: new_ident(name),
-            semi_token: Token![;](Span::call_site()),
         }
     }
 }
 
 impl Parse for NameDef {
-    /// name_def : "let" "name" '=' Ident ';' ;
+    /// name_def : "named" Ident ;
     fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
         Ok(NameDef {
-            let_token: input.parse()?,
-            name_ident: check_ident(input.parse()?, Self::NAME_IDENT, Self::NAME_IDENT_ERR)?,
-            eq_token: input.parse()?,
+            named_ident: check_ident(input.parse()?, Self::NAME_IDENT, Self::NAME_IDENT_ERR)?,
             name: input.parse()?,
-            semi_token: input.parse()?,
         })
     }
 }
 
 impl GetSpan for NameDef {
     fn span(&self) -> Span {
-        self.let_token
-            .span()
-            .left_join(self.name_ident.span())
-            .left_join(self.eq_token.span())
-            .left_join(self.name.span())
-            .left_join(self.semi_token.span())
+        self.named_ident.span().left_join(self.name.span())
     }
 }
 
 #[cfg_attr(test, derive(Debug, PartialEq))]
-pub(crate) struct StatesDef {
-    pub(crate) states: IdentArray,
+pub(crate) struct VersionDef {
+    version_ident: Ident,
+    literal: LitInt,
+    version: u64,
+}
+
+impl VersionDef {
+    const VERSION_IDENT: &str = "version";
+    const VERSION_IDENT_ERR: &str = "Invalid version specifier. Expected 'version'.";
+
+    #[cfg(test)]
+    pub(crate) fn new(version: u64) -> Self {
+        Self {
+            version_ident: new_ident("version"),
+            literal: LitInt::new(&version.to_string(), Span::call_site()),
+            version,
+        }
+    }
+
+    #[allow(dead_code)]
+    pub(crate) fn version(&self) -> u64 {
+        self.version
+    }
+}
+
+impl Parse for VersionDef {
+    /// version_def: "version" LitInt;
+    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+        let version_ident =
+            check_ident(input.parse()?, Self::VERSION_IDENT, Self::VERSION_IDENT_ERR)?;
+        let literal: LitInt = input.parse()?;
+        let version = literal.base10_parse()?;
+        Ok(Self {
+            version_ident,
+            literal,
+            version,
+        })
+    }
 }
 
-impl StatesDef {
-    const STATES_ARRAY_IDENT: &str = "states";
-    const ARRAY_IDENT_ERR: &str = "invalid states array identifier. Expected 'states'.";
+impl GetSpan for VersionDef {
+    fn span(&self) -> Span {
+        self.version_ident.span().left_join(self.literal.span())
+    }
+}
+
+#[cfg_attr(test, derive(Debug, PartialEq))]
+pub(crate) struct ActorDef {
+    let_token: Token![let],
+    pub(crate) actor: Ident,
+    eq_token: Token![=],
+    pub(crate) states: IdentArray,
 }
 
 #[cfg(test)]
-impl StatesDef {
-    pub(crate) fn new(state_names: impl IntoIterator<Item = &'static str>) -> Self {
+impl ActorDef {
+    pub(crate) fn new(actor: &str, state_names: impl IntoIterator<Item = &'static str>) -> Self {
         Self {
+            let_token: Token![let](Span::call_site()),
+            actor: new_ident(actor),
+            eq_token: Token![=](Span::call_site()),
             states: IdentArray::new(state_names),
         }
     }
 }
 
-impl Parse for StatesDef {
-    /// states_def : "let" "states" '=' ident_array ';' ;
+impl Parse for ActorDef {
+    /// actor_def : "let" Ident '=' ident_array ;
     fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
-        input.parse::<Token![let]>()?;
-        if Ident::parse(input)? != Self::STATES_ARRAY_IDENT {
-            return Err(input.error(Self::ARRAY_IDENT_ERR));
-        };
-        input.parse::<Token![=]>()?;
-        let ident_array = IdentArray::parse(input)?;
-        input.parse::<Token![;]>()?;
-        Ok(StatesDef {
-            states: ident_array,
+        Ok(Self {
+            let_token: input.parse()?,
+            actor: input.parse()?,
+            eq_token: input.parse()?,
+            states: input.parse()?,
         })
     }
 }
 
-impl GetSpan for StatesDef {
+impl GetSpan for ActorDef {
     fn span(&self) -> Span {
-        self.states.span()
+        self.let_token
+            .span()
+            .left_join(self.actor.span())
+            .left_join(self.eq_token.span())
+            .left_join(&self.states)
     }
 }
 
 #[cfg_attr(test, derive(Debug))]
 #[derive(Hash, PartialEq, Eq)]
-pub(crate) struct IdentArray(Punctuated<Ident, Token![,]>);
+pub(crate) struct IdentArray {
+    bracket: Bracket,
+    idents: Punctuated<Ident, Token![,]>,
+}
 
 impl IdentArray {
     const EMPTY_ERR: &str = "at least one state is required";
 
     fn empty() -> Self {
-        Self(Punctuated::new())
+        Self {
+            bracket: Bracket::default(),
+            idents: Punctuated::new(),
+        }
     }
 }
 
 #[cfg(test)]
 impl IdentArray {
     pub(crate) fn new(state_names: impl IntoIterator<Item = &'static str>) -> Self {
-        Self(state_names.into_iter().map(new_ident).collect())
+        Self {
+            bracket: Bracket::default(),
+            idents: state_names.into_iter().map(new_ident).collect(),
+        }
     }
 }
 
 impl GetSpan for IdentArray {
     fn span(&self) -> Span {
-        self.0.span()
+        let delim_span = &self.bracket.span;
+        delim_span
+            .open()
+            .left_join(self.idents.span())
+            .left_join(delim_span.close())
     }
 }
 
@@ -173,31 +257,37 @@ impl Parse for IdentArray {
     /// ident_array : '[' Ident ( ',' Ident )* ','? ']' ;
     fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
         let content;
-        let bracket_token = bracketed!(content in input);
-        let states = content.parse_terminated(Ident::parse, Token![,])?;
-        if states.is_empty() {
-            return Err(syn::Error::new(bracket_token.span.open(), Self::EMPTY_ERR));
+        let bracket = bracketed!(content in input);
+        let idents = content.parse_terminated(Ident::parse, Token![,])?;
+        if idents.is_empty() {
+            return Err(syn::Error::new(bracket.span.open(), Self::EMPTY_ERR));
         }
-        Ok(Self(states))
+        Ok(Self { bracket, idents })
     }
 }
 
 impl AsRef<Punctuated<Ident, Token![,]>> for IdentArray {
     fn as_ref(&self) -> &Punctuated<Ident, Token![,]> {
-        &self.0
+        &self.idents
     }
 }
 
 #[cfg_attr(test, derive(Debug, PartialEq))]
 pub(crate) struct Transition {
     pub(crate) in_state: State,
-    pub(crate) in_msg: Option<Message>,
+    in_msg: Option<(Token![?], Message)>,
     arrow: Token![->],
     pub(crate) out_states: StatesList,
     redirect: Option<Token![>]>,
     pub(crate) out_msgs: DestList,
 }
 
+impl Transition {
+    pub(crate) fn in_msg(&self) -> Option<&Message> {
+        self.in_msg.as_ref().map(|(_, msg)| msg)
+    }
+}
+
 #[cfg(test)]
 impl Transition {
     pub(crate) fn new(
@@ -214,7 +304,7 @@ impl Transition {
         };
         Self {
             in_state,
-            in_msg,
+            in_msg: in_msg.map(|msg| (Token![?](Span::call_site()), msg)),
             arrow: Token![->](Span::call_site()),
             out_states: StatesList(out_states.into_iter().collect()),
             redirect,
@@ -227,8 +317,8 @@ impl Parse for Transition {
     /// transition : state ( '?' message )?  "->" states_list ( '>' dest_list )? ;
     fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
         let in_state = State::parse(input)?;
-        let in_msg = if input.parse::<Token![?]>().is_ok() {
-            Some(Message::parse(input)?)
+        let in_msg = if let Ok(question_mark) = input.parse::<Token![?]>() {
+            Some((question_mark, Message::parse(input)?))
         } else {
             None
         };
@@ -254,7 +344,7 @@ impl GetSpan for Transition {
     fn span(&self) -> Span {
         self.in_state
             .span()
-            .left_join(self.in_msg.as_ref())
+            .left_join(self.in_msg.as_ref().map(|(x, y)| x.span().left_join(y)))
             .left_join(self.arrow.span())
             .left_join(&self.out_states)
             .left_join(self.redirect.as_ref().map(|x| x.span()))
@@ -290,7 +380,7 @@ impl Parse for State {
     /// state : Ident ident_array? ;
     fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
         let state_trait = Ident::parse(input)?;
-        let owned_states = if input.peek(token::Bracket) {
+        let owned_states = if input.peek(Bracket) {
             IdentArray::parse(input)?
         } else {
             IdentArray::empty()
@@ -382,29 +472,38 @@ impl AsRef<Punctuated<Dest, Token![,]>> for DestList {
 #[cfg_attr(test, derive(Debug, PartialEq))]
 pub(crate) struct Dest {
     pub(crate) state: DestinationState,
+    exclamation: Token![!],
     pub(crate) msg: Message,
 }
 
 #[cfg(test)]
 impl Dest {
     pub(crate) fn new(state: DestinationState, msg: Message) -> Self {
-        Self { state, msg }
+        Self {
+            state,
+            exclamation: Token![!](Span::call_site()),
+            msg,
+        }
     }
 }
 
 impl Parse for Dest {
     /// dest : dest_state '!' message
     fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
-        let state = DestinationState::parse(input)?;
-        input.parse::<Token![!]>()?;
-        let msg = Message::parse(input)?;
-        Ok(Self { state, msg })
+        Ok(Self {
+            state: input.parse()?,
+            exclamation: input.parse()?,
+            msg: input.parse()?,
+        })
     }
 }
 
 impl GetSpan for Dest {
     fn span(&self) -> Span {
-        self.state.span().left_join(&self.msg)
+        self.state
+            .span()
+            .left_join(self.exclamation.span())
+            .left_join(&self.msg)
     }
 }
 
@@ -469,8 +568,8 @@ pub(crate) struct Message {
 impl Message {
     /// Returns the identifier to use when naming types and variants after this message.
     pub(crate) fn ident(&self) -> &Ident {
-        if let Some(variant) = &self.ident {
-            variant
+        if let Some(ident) = &self.ident {
+            ident
         } else {
             &self.msg_type
         }
@@ -521,10 +620,10 @@ impl Parse for Message {
         } else {
             (None, None)
         };
-        let owned_states = if input.peek(token::Bracket) {
+        let owned_states = if input.peek(Bracket) {
             IdentArray::parse(input)?
         } else {
-            IdentArray(Punctuated::new())
+            IdentArray::empty()
         };
         Ok(Self {
             msg_type,
@@ -537,11 +636,10 @@ impl Parse for Message {
 
 impl GetSpan for Message {
     fn span(&self) -> Span {
-        let mut span = self.msg_type.span();
-        if let Some(reply_part) = &self.reply_part {
-            span = span.left_join(reply_part.span());
-        }
-        span.left_join(self.owned_states.span())
+        self.msg_type
+            .span()
+            .left_join(self.reply_part.as_ref())
+            .left_join(&self.owned_states)
     }
 }
 
@@ -650,11 +748,12 @@ mod tests {
 
     #[test]
     fn protocol_parse_minimal() {
+        const EXPECTED_ACTOR: &str = "server";
         const EXPECTED_NAME: &str = "Foo";
         const EXPECTED_STATES: [&str; 3] = ["First", "Second", "Third"];
         let input = format!(
-            "let name = {EXPECTED_NAME};
-let states = [{}];
+            "named {EXPECTED_NAME};
+let {EXPECTED_ACTOR} = [{}];
 {} -> {};
 {} -> {};",
             EXPECTED_STATES.join(", "),
@@ -665,7 +764,7 @@ let states = [{}];
         );
         let expected = Protocol::new(
             NameDef::new(EXPECTED_NAME),
-            StatesDef::new(EXPECTED_STATES),
+            ActorDef::new(EXPECTED_ACTOR, EXPECTED_STATES),
             [
                 Transition::new(
                     State::new(EXPECTED_STATES[0], []),
@@ -687,10 +786,62 @@ let states = [{}];
         assert_eq!(expected, actual);
     }
 
+    #[test]
+    fn protocol_parse_with_version() {
+        const EXPECTED_VERSION: u64 = 37;
+        let input = format!(
+            "named VersionTest;
+version {EXPECTED_VERSION};
+let actor = [Init];
+Init?Activate -> End;"
+        );
+        let expected = Protocol::with_version(
+            NameDef::new("VersionTest"),
+            VersionDef::new(EXPECTED_VERSION),
+            ActorDef::new("actor", ["Init"]),
+            [Transition::new(
+                State::new("Init", []),
+                Some(Message::new("Activate", false, [])),
+                [State::new("End", [])],
+                [],
+            )],
+        );
+
+        let actual = parse_str::<Protocol>(&input).unwrap();
+
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn protocol_parse_version_mismatch_is_err() {
+        const EXPECTED_VERSION: u64 = 37;
+        let input = format!(
+            "named VersionTest;
+version {EXPECTED_VERSION};
+let actor = [Init];
+Init?Activate -> End;"
+        );
+        let expected = Protocol::with_version(
+            NameDef::new("VersionTest"),
+            VersionDef::new(EXPECTED_VERSION + 1),
+            ActorDef::new("actor", ["Init"]),
+            [Transition::new(
+                State::new("Init", []),
+                Some(Message::new("Activate", false, [])),
+                [State::new("End", [])],
+                [],
+            )],
+        );
+
+        let actual = parse_str::<Protocol>(&input).unwrap();
+
+        assert_ne!(expected, actual);
+    }
+
     #[test]
     fn name_def_parse() {
         const EXPECTED_NAME: &str = "Foofercorg";
-        let input = format!("let name = {EXPECTED_NAME};");
+        let input = format!("named {EXPECTED_NAME}");
         let expected = NameDef::new(EXPECTED_NAME);
 
         let actual = parse_str::<NameDef>(&input).unwrap();
@@ -700,7 +851,7 @@ let states = [{}];
 
     #[test]
     fn name_def_wrong_ident_err() {
-        let result = parse_str::<NameDef>("let nmae = Shodan;");
+        let result = parse_str::<NameDef>("nmaed Shodan");
 
         assert!(result.is_err());
         let err_str = result.err().unwrap().to_string();
@@ -708,23 +859,35 @@ let states = [{}];
     }
 
     #[test]
-    fn states_def_parse() {
-        const EXPECTED_STATES: [&str; 2] = ["First", "Second"];
-        let input = format!("let states = [{}];", EXPECTED_STATES.join(", "));
-        let expected = StatesDef::new(EXPECTED_STATES);
+    fn version_def_parse() {
+        const EXPECTED_VERSION: u64 = 1;
+        let input = format!("version {EXPECTED_VERSION}");
+        let expected = VersionDef::new(EXPECTED_VERSION);
 
-        let actual = parse_str::<StatesDef>(&input).unwrap();
+        let actual = parse_str::<VersionDef>(&input).unwrap();
 
         assert_eq!(expected, actual);
     }
 
     #[test]
-    fn states_def_parse_wrong_ident_err() {
-        let result = parse_str::<StatesDef>("let staties = [Alpha, Beta];");
+    fn version_def_parse_wrong_ident_err() {
+        let result = parse_str::<VersionDef>("versoin 3");
 
         assert!(result.is_err());
         let err_str = result.err().unwrap().to_string();
-        assert_eq!(StatesDef::ARRAY_IDENT_ERR, err_str);
+        assert_eq!(VersionDef::VERSION_IDENT_ERR, err_str);
+    }
+
+    #[test]
+    fn actor_def_parse() {
+        const EXPECTED_ACTOR: &str = "server";
+        const EXPECTED_STATES: [&str; 2] = ["First", "Second"];
+        let input = format!("let {EXPECTED_ACTOR} = [{}]", EXPECTED_STATES.join(", "));
+        let expected = ActorDef::new(EXPECTED_ACTOR, EXPECTED_STATES);
+
+        let actual = parse_str::<ActorDef>(&input).unwrap();
+
+        assert_eq!(expected, actual);
     }
 
     #[test]
@@ -733,9 +896,9 @@ let states = [{}];
 
         let actual = IdentArray::new(EXPECTED);
 
-        assert_eq!(EXPECTED.len(), actual.0.len());
-        assert_eq!(actual.0[0], EXPECTED[0]);
-        assert_eq!(actual.0[1], EXPECTED[1]);
+        assert_eq!(EXPECTED.len(), actual.idents.len());
+        assert_eq!(actual.idents[0], EXPECTED[0]);
+        assert_eq!(actual.idents[1], EXPECTED[1]);
     }
 
     #[test]
@@ -1004,9 +1167,12 @@ let states = [{}];
 
         assert_eq!(actual.msg_type, EXPECTED_MSG_TYPE);
         assert_eq!(actual.is_reply(), EXPECTED_IS_REPLY);
-        assert_eq!(actual.owned_states.0.len(), EXPECTED_OWNED_STATES.len());
-        assert_eq!(actual.owned_states.0[0], EXPECTED_OWNED_STATES[0]);
-        assert_eq!(actual.owned_states.0[1], EXPECTED_OWNED_STATES[1]);
+        assert_eq!(
+            actual.owned_states.idents.len(),
+            EXPECTED_OWNED_STATES.len()
+        );
+        assert_eq!(actual.owned_states.idents[0], EXPECTED_OWNED_STATES[0]);
+        assert_eq!(actual.owned_states.idents[1], EXPECTED_OWNED_STATES[1]);
     }
 
     #[test]

+ 24 - 24
crates/btproto/src/validation.rs

@@ -38,7 +38,7 @@ impl Protocol {
             let in_state = &transition.in_state;
             used.insert(&in_state.state_trait);
             used.extend(in_state.owned_states.as_ref().iter());
-            if let Some(in_msg) = &transition.in_msg {
+            if let Some(in_msg) = transition.in_msg() {
                 used.extend(in_msg.owned_states.as_ref().iter());
             }
             for out_states in transition.out_states.as_ref().iter() {
@@ -71,7 +71,7 @@ impl Protocol {
         let mut senders: HashSet<(&State, &Message)> = HashSet::new();
         let mut receivers: HashSet<(&State, &Message)> = HashSet::new();
         for transition in self.transitions.iter() {
-            if let Some(msg) = &transition.in_msg {
+            if let Some(msg) = transition.in_msg() {
                 receivers.insert((&transition.in_state, msg));
                 if msg.msg_type == Activate::ident() {
                     // The Activate message is sent by the run time, so a sender is created to
@@ -169,7 +169,7 @@ impl Protocol {
                         .collect(),
                 );
             }
-            if transition.in_msg.is_none() {
+            if transition.in_msg().is_none() {
                 err = err.combine(
                     replies
                         .iter()
@@ -192,7 +192,7 @@ impl Protocol {
         self.transitions
             .iter()
             .filter(|transition| {
-                transition.in_msg.is_none() && transition.out_msgs.as_ref().is_empty()
+                transition.in_msg().is_none() && transition.out_msgs.as_ref().is_empty()
             })
             .map(|transition| syn::Error::new(transition.span(), Self::NO_MSG_SENT_OR_RECEIVED_ERR))
             .collect()
@@ -202,7 +202,7 @@ impl Protocol {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::parsing::{Dest, NameDef, StatesDef, Transition};
+    use crate::parsing::{ActorDef, Dest, NameDef, Transition};
 
     macro_rules! assert_ok {
         ($maybe_err:expr) => {
@@ -224,7 +224,7 @@ mod tests {
         const STATE_NAME: &str = "Init";
         Protocol::new(
             NameDef::new("Test"),
-            StatesDef::new([STATE_NAME]),
+            ActorDef::new("actor", [STATE_NAME]),
             [Transition::new(
                 State::new(STATE_NAME, []),
                 Some(Message::new("Activate", false, [])),
@@ -246,7 +246,7 @@ mod tests {
         const STATE_NAME: &str = "Init";
         let input = Protocol::new(
             NameDef::new("Test"),
-            StatesDef::new([STATE_NAME]),
+            ActorDef::new("actor", [STATE_NAME]),
             [Transition::new(
                 State::new(STATE_NAME, []),
                 Some(Message::new("Activate", false, [])),
@@ -264,7 +264,7 @@ mod tests {
     fn all_states_declared_and_used_undeclared_err() {
         let input = Protocol::new(
             NameDef::new("Undeclared"),
-            StatesDef::new(["Init"]),
+            ActorDef::new("actor", ["Init"]),
             [Transition::new(
                 State::new("Init", []),
                 Some(Message::new("Activate", false, [])),
@@ -282,7 +282,7 @@ mod tests {
     fn all_states_declared_and_used_undeclared_out_state_owned_err() {
         let input = Protocol::new(
             NameDef::new("Undeclared"),
-            StatesDef::new(["Init", "Next"]),
+            ActorDef::new("actor", ["Init", "Next"]),
             [Transition::new(
                 State::new("Init", []),
                 Some(Message::new("Activate", false, [])),
@@ -300,7 +300,7 @@ mod tests {
     fn all_states_declared_and_used_undeclared_in_state_owned_err() {
         let input = Protocol::new(
             NameDef::new("Undeclared"),
-            StatesDef::new(["Init", "Next"]),
+            ActorDef::new("actor", ["Init", "Next"]),
             [Transition::new(
                 State::new("Init", ["Undeclared"]),
                 Some(Message::new("Activate", false, [])),
@@ -318,7 +318,7 @@ mod tests {
     fn all_states_declared_and_used_unused_err() {
         let input = Protocol::new(
             NameDef::new("Unused"),
-            StatesDef::new(["Init", "Extra"]),
+            ActorDef::new("actor", ["Init", "Extra"]),
             [Transition::new(
                 State::new("Init", []),
                 Some(Message::new("Activate", false, [])),
@@ -343,7 +343,7 @@ mod tests {
     fn match_receivers_and_senders_send_activate_ok() {
         let input = Protocol::new(
             NameDef::new("Unbalanced"),
-            StatesDef::new(["First", "Second"]),
+            ActorDef::new("actor", ["First", "Second"]),
             [
                 Transition::new(
                     State::new("First", []),
@@ -372,7 +372,7 @@ mod tests {
     fn match_receivers_and_senders_unmatched_sender_err() {
         let input = Protocol::new(
             NameDef::new("Unbalanced"),
-            StatesDef::new(["Init", "Other"]),
+            ActorDef::new("actor", ["Init", "Other"]),
             [Transition::new(
                 State::new("Init", []),
                 Some(Message::new("Activate", false, [])),
@@ -393,7 +393,7 @@ mod tests {
     fn match_receivers_and_senders_unmatched_receiver_err() {
         let input = Protocol::new(
             NameDef::new("Unbalanced"),
-            StatesDef::new(["Init"]),
+            ActorDef::new("actor", ["Init"]),
             [Transition::new(
                 State::new("Init", []),
                 Some(Message::new("NotExists", false, [])),
@@ -418,7 +418,7 @@ mod tests {
     fn no_undeliverable_msgs_reply_ok() {
         let input = Protocol::new(
             NameDef::new("Undeliverable"),
-            StatesDef::new(["Listening", "Client"]),
+            ActorDef::new("actor", ["Listening", "Client"]),
             [Transition::new(
                 State::new("Listening", []),
                 Some(Message::new("Msg", false, [])),
@@ -439,7 +439,7 @@ mod tests {
     fn no_undeliverable_msgs_service_ok() {
         let input = Protocol::new(
             NameDef::new("Undeliverable"),
-            StatesDef::new(["Client", "Server"]),
+            ActorDef::new("actor", ["Client", "Server"]),
             [Transition::new(
                 State::new("Client", []),
                 None,
@@ -460,7 +460,7 @@ mod tests {
     fn no_undeliverable_msgs_owned_ok() {
         let input = Protocol::new(
             NameDef::new("Undeliverable"),
-            StatesDef::new(["FileClient", "FileHandle"]),
+            ActorDef::new("actor", ["FileClient", "FileHandle"]),
             [Transition::new(
                 State::new("FileClient", ["FileHandle"]),
                 None,
@@ -481,7 +481,7 @@ mod tests {
     fn no_undeliverable_msgs_err() {
         let input = Protocol::new(
             NameDef::new("Undeliverable"),
-            StatesDef::new(["Client", "Server"]),
+            ActorDef::new("actor", ["Client", "Server"]),
             [Transition::new(
                 State::new("Client", []),
                 None,
@@ -502,7 +502,7 @@ mod tests {
     fn valid_replies_ok() {
         let input = Protocol::new(
             NameDef::new("ValidReplies"),
-            StatesDef::new(["Client", "Server"]),
+            ActorDef::new("actor", ["Client", "Server"]),
             [Transition::new(
                 State::new("Server", []),
                 Some(Message::new("Msg", false, [])),
@@ -523,7 +523,7 @@ mod tests {
     fn valid_replies_invalid_reply_err() {
         let input = Protocol::new(
             NameDef::new("ValidReplies"),
-            StatesDef::new(["Client", "Server"]),
+            ActorDef::new("actor", ["Client", "Server"]),
             [Transition::new(
                 State::new("Client", []),
                 None,
@@ -544,7 +544,7 @@ mod tests {
     fn valid_replies_multiple_replies_err() {
         let input = Protocol::new(
             NameDef::new("ValidReplies"),
-            StatesDef::new(["Client", "OtherClient", "Server"]),
+            ActorDef::new("actor", ["Client", "OtherClient", "Server"]),
             [Transition::new(
                 State::new("Server", []),
                 Some(Message::new("Msg", false, [])),
@@ -571,7 +571,7 @@ mod tests {
     fn msg_sent_or_received_msg_received_ok() {
         let input = Protocol::new(
             NameDef::new("Test"),
-            StatesDef::new(["Init"]),
+            ActorDef::new("actor", ["Init"]),
             [Transition::new(
                 State::new("Init", []),
                 Some(Message::new("Activate", false, [])),
@@ -589,7 +589,7 @@ mod tests {
     fn msg_sent_or_received_msg_sent_ok() {
         let input = Protocol::new(
             NameDef::new("Test"),
-            StatesDef::new(["First", "Second"]),
+            ActorDef::new("actor", ["First", "Second"]),
             [Transition::new(
                 State::new("First", []),
                 None,
@@ -610,7 +610,7 @@ mod tests {
     fn msg_sent_or_received_neither_err() {
         let input = Protocol::new(
             NameDef::new("Test"),
-            StatesDef::new(["First"]),
+            ActorDef::new("actor", ["First"]),
             [Transition::new(
                 State::new("First", []),
                 None,

+ 2 - 2
crates/btproto/tests/protocol_tests.rs

@@ -22,7 +22,7 @@ macro_rules! assert_type {
 #[test]
 fn minimal_syntax() {
     protocol! {
-        let name = MinimalTest;
+        named MinimalTest;
         let states = [Init];
         Init?Activate -> End;
     }
@@ -46,7 +46,7 @@ fn minimal_syntax() {
 #[test]
 fn reply() {
     protocol! {
-        let name = ReplyTest;
+        named ReplyTest;
         let states = [
             ServerInit, Listening,
             Client, Waiting,

+ 2 - 2
crates/btrun/tests/runtime_tests.rs

@@ -153,7 +153,7 @@ mod ping_pong {
     // The following code is a proof-of-concept for what types should be generated for a
     // simple ping-pong protocol:
     protocol! {
-        let name = PingPongProtocol;
+        named PingPongProtocol;
         let states = [
             ClientInit, SentPing,
             ServerInit, Listening,
@@ -377,7 +377,7 @@ mod travel_agency {
     // message because there is a transition from Choosing that doesn't use the receive operator
     // (`?`).
     protocol! {
-        let name = TravelAgency;
+        named TravelAgency;
         let states = [
             AgencyInit, Listening,
             Choosing,

+ 1 - 1
crates/btsector/src/lib.rs

@@ -58,7 +58,7 @@ pub enum SectorMsgReply {
 }
 
 protocol! {
-    let name = SectorProtocol;
+    named SectorProtocol;
     let states = [ServerInit, Listening, Client];
     ServerInit?Activate -> Listening;
     Client -> Client, >service(Listening)!SectorMsg;