|
@@ -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));
|
|
|
Self {
|
|
|
name_def,
|
|
|
+ name_def_semi: Token),
|
|
|
+ version_def: None,
|
|
|
states_def,
|
|
|
+ states_def_semi: Token),
|
|
|
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)));
|
|
|
+ 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),
|
|
|
- name_ident: new_ident("name"),
|
|
|
- eq_token: Token),
|
|
|
+ named_ident: new_ident(Self::NAME_IDENT),
|
|
|
name: new_ident(name),
|
|
|
- semi_token: Token),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
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),
|
|
|
+ actor: new_ident(actor),
|
|
|
+ eq_token: Token),
|
|
|
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), msg)),
|
|
|
arrow: Token),
|
|
|
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),
|
|
|
+ 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]
|