#![allow(dead_code, unused_imports)]
use crate::ast::{
Allocate, AttributeBody, AttributeUsage, Bind, Connect, ConnectBody, ConnectionUsageMember,
DefinitionPrefix, ExhibitState, Expression, InOut, InterfaceUsage, InterfaceUsageBodyElement,
Node, OpaqueMemberDecl, PartDef, PartDefBody, PartDefBodyElement, PartUsage, PartUsageBody,
PartUsageBodyElement, Perform, PerformBody, PerformBodyElement, PerformInOutBinding, RefBody,
RefDecl,
};
use crate::parser::attribute::{attribute_def, attribute_usage, attribute_usage_shorthand};
use crate::parser::build_recovery_error_node_from_span;
use crate::parser::connection::connection_member_body;
use crate::parser::expr::{expression, path_expression};
use crate::parser::interface::connect_body;
use crate::parser::lex::{
identification, name, qualified_name, recover_body_element, skip_until_brace_end,
specialization_operator, starts_with_any_keyword, take_until_terminator, ws1, ws_and_comments,
PART_BODY_STARTERS,
};
use crate::parser::metadata_annotation::{annotation, metadata_annotation};
use crate::parser::occurrence::{
individual_usage, occurrence_usage, snapshot_usage, then_timeslice_usage, timeslice_usage,
};
use crate::parser::port::port_usage;
use crate::parser::requirement::{comment_annotation, doc_comment, requirement_usage, satisfy};
use crate::parser::with_span;
use crate::parser::Input;
use crate::parser::{node_from_to, span_from_to};
use nom::branch::alt;
use nom::bytes::complete::{tag, take_until};
use nom::combinator::{map, opt, value};
use nom::multi::many0;
use nom::sequence::delimited;
use nom::sequence::preceded;
use nom::IResult;
use nom::Parser;
#[derive(Debug)]
#[allow(clippy::large_enum_variant)]
pub(crate) enum PartDefOrUsage {
Def(Node<PartDef>),
Usage(Node<PartUsage>),
}
pub(crate) fn part_def_body(input: Input<'_>) -> IResult<Input<'_>, PartDefBody> {
let (input, _) = ws_and_comments(input)?;
alt((
map(tag(&b";"[..]), |_| PartDefBody::Semicolon),
part_def_body_brace,
))
.parse(input)
}
fn part_def_body_brace(input: Input<'_>) -> IResult<Input<'_>, PartDefBody> {
let (mut input, _) = tag(&b"{"[..]).parse(input)?;
let mut elements = Vec::new();
loop {
let (next, _) = ws_and_comments(input)?;
input = next;
if input.fragment().is_empty() {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Eof,
)));
}
if input.fragment().starts_with(b"}") {
let (input, _) = preceded(ws_and_comments, tag(&b"}"[..])).parse(input)?;
return Ok((input, PartDefBody::Brace { elements }));
}
match part_def_body_element(input) {
Ok((next, element)) => {
if next.location_offset() == input.location_offset() {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Many0,
)));
}
elements.push(element);
input = next;
}
Err(_) if starts_with_any_keyword(input.fragment(), PART_BODY_STARTERS) => {
let (next, _) = recover_body_element(input, PART_BODY_STARTERS)?;
if next.location_offset() == input.location_offset() {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Many0,
)));
}
elements.push(node_from_to(
input,
next,
PartDefBodyElement::Error(Node::new(
crate::ast::Span::dummy(),
build_recovery_error_node_from_span(
input,
next,
PART_BODY_STARTERS,
"part definition body",
"recovered_part_def_body_element",
),
)),
));
input = next;
}
Err(_) => {
let start_unknown = input;
let recovery = build_recovery_error_node_from_span(
start_unknown,
next,
PART_BODY_STARTERS,
"part definition body",
"recovered_part_def_body_element",
);
let (next, _) = recover_body_element(input, PART_BODY_STARTERS)?;
if next.location_offset() == start_unknown.location_offset() {
let (input, _) = skip_until_brace_end(input)?;
let (input, _) = preceded(ws_and_comments, tag(&b"}"[..])).parse(input)?;
return Ok((input, PartDefBody::Brace { elements }));
}
if matches!(
recovery.code.as_str(),
"missing_member_name" | "missing_type_reference"
) {
elements.push(node_from_to(
start_unknown,
next,
PartDefBodyElement::Error(Node::new(crate::ast::Span::dummy(), recovery)),
));
} else {
let frag = start_unknown.fragment();
let take = frag.len().min(80);
let preview = String::from_utf8_lossy(&frag[..take]).trim().to_string();
elements.push(node_from_to(
start_unknown,
next,
PartDefBodyElement::Other(preview),
));
}
input = next;
}
}
}
}
fn exhibit_state(input: Input<'_>) -> IResult<Input<'_>, Node<ExhibitState>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, _) = tag(&b"exhibit"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, _) = tag(&b"state"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, name_str) = name(input)?;
let (input, type_name) = opt(preceded(
preceded(ws_and_comments, tag(&b":"[..])),
preceded(ws_and_comments, qualified_name),
))
.parse(input)?;
let (input, body) = crate::parser::state::state_def_body(input)?;
let (input, redefines) = opt(preceded(
preceded(ws_and_comments, tag(&b":>>"[..])),
preceded(ws_and_comments, qualified_name),
))
.parse(input)?;
let input = if redefines.is_some() {
let (input, _) = preceded(ws_and_comments, tag(&b";"[..])).parse(input)?;
input
} else {
input
};
Ok((
input,
node_from_to(
start,
input,
ExhibitState {
name: name_str,
type_name,
redefines,
body,
},
),
))
}
fn part_def_body_element(input: Input<'_>) -> IResult<Input<'_>, Node<PartDefBodyElement>> {
let (input, _) = ws_and_comments(input)?;
let start = input;
let (input, elem) = alt((
alt((
map(doc_comment, PartDefBodyElement::Doc),
map(comment_annotation, PartDefBodyElement::Comment),
map(annotation, PartDefBodyElement::Annotation),
map(exhibit_state, PartDefBodyElement::ExhibitState),
map(perform_action_decl, PartDefBodyElement::Perform),
map(perform_usage, PartDefBodyElement::Perform),
map(allocate_, PartDefBodyElement::Allocate),
map(connection_usage_member, PartDefBodyElement::Connection),
map(connect_, PartDefBodyElement::Connect),
map(part_usage, |p| PartDefBodyElement::PartUsage(Box::new(p))),
map(individual_usage, |n| {
PartDefBodyElement::OccurrenceUsage(Box::new(n))
}),
map(snapshot_usage, |n| {
PartDefBodyElement::OccurrenceUsage(Box::new(n))
}),
)),
alt((
map(timeslice_usage, |n| {
PartDefBodyElement::OccurrenceUsage(Box::new(n))
}),
map(then_timeslice_usage, |n| {
PartDefBodyElement::OccurrenceUsage(Box::new(n))
}),
map(occurrence_usage, |n| {
PartDefBodyElement::OccurrenceUsage(Box::new(n))
}),
map(interface_usage, PartDefBodyElement::InterfaceUsage),
map(port_usage, PartDefBodyElement::PortUsage),
map(part_ref_usage, PartDefBodyElement::Ref),
map(attribute_usage, PartDefBodyElement::AttributeUsage),
map(attribute_def, PartDefBodyElement::AttributeDef),
map(
attribute_usage_shorthand,
PartDefBodyElement::AttributeUsage,
),
map(requirement_usage, PartDefBodyElement::RequirementUsage),
map(opaque_part_member_decl, PartDefBodyElement::OpaqueMember),
)),
))
.parse(input)?;
Ok((input, node_from_to(start, input, elem)))
}
fn connection_usage_member(input: Input<'_>) -> IResult<Input<'_>, Node<ConnectionUsageMember>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, _) = tag(&b"connection"[..]).parse(input)?;
let (input, _) = ws_and_comments(input)?;
let (input, name) = if input.fragment().starts_with(b":")
|| input.fragment().starts_with(b"{")
|| input.fragment().starts_with(b";")
{
(input, None)
} else {
let (input, parsed_name) = name(input)?;
(input, Some(parsed_name))
};
let (input, type_name) = {
let (peek, _) = ws_and_comments(input)?;
if peek.fragment().starts_with(b":")
&& !peek.fragment().starts_with(b":>")
&& !peek.fragment().starts_with(b":>>")
{
let (input, _) = preceded(ws_and_comments, tag(&b":"[..])).parse(input)?;
let (input, parsed_type) = preceded(ws_and_comments, qualified_name).parse(input)?;
(input, Some(parsed_type))
} else {
(input, None)
}
};
let (input, body) = connection_member_body(input)?;
let (input, trailing_subsets) = opt(preceded(
preceded(ws_and_comments, tag(&b":>"[..])),
preceded(ws_and_comments, qualified_name),
))
.parse(input)?;
let (input, trailing_redefines) = opt(preceded(
preceded(ws_and_comments, tag(&b":>>"[..])),
preceded(ws_and_comments, qualified_name),
))
.parse(input)?;
let input = if trailing_subsets.is_some() || trailing_redefines.is_some() {
let (input, _) = preceded(ws_and_comments, tag(&b";"[..])).parse(input)?;
input
} else {
input
};
Ok((
input,
node_from_to(
start,
input,
ConnectionUsageMember {
name,
type_name,
body,
subsets: trailing_subsets,
redefines: trailing_redefines,
},
),
))
}
fn opaque_part_member_decl(input: Input<'_>) -> IResult<Input<'_>, Node<OpaqueMemberDecl>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, _) = opt(preceded(tag(&b"abstract"[..]), ws1)).parse(input)?;
if !starts_with_any_keyword(
input.fragment(),
&[b"ref", b"action", b"state", b"port", b"connection"],
) {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Tag,
)));
}
let (input, header_text) = take_until_terminator(input, b";{")?;
let keyword = if starts_with_any_keyword(input.fragment(), &[b"ref"]) {
"ref"
} else if starts_with_any_keyword(input.fragment(), &[b"action"]) {
"action"
} else if starts_with_any_keyword(input.fragment(), &[b"state"]) {
"state"
} else if starts_with_any_keyword(input.fragment(), &[b"connection"]) {
"connection"
} else {
"port"
}
.to_string();
let name_str = header_text
.split(|c: char| {
c.is_whitespace() || c == ':' || c == '[' || c == ',' || c == '(' || c == ')'
})
.filter(|s| !s.is_empty())
.find(|token| {
!matches!(
*token,
"ref"
| "action"
| "state"
| "port"
| "connection"
| "part"
| "private"
| "protected"
| "public"
)
})
.unwrap_or("member")
.to_string();
let (input, _) = ws_and_comments(input)?;
let (input, body) = alt((
map(tag(&b";"[..]), |_| AttributeBody::Semicolon),
map(
delimited(
tag(&b"{"[..]),
skip_until_brace_end,
preceded(ws_and_comments, tag(&b"}"[..])),
),
|_| AttributeBody::Brace,
),
))
.parse(input)?;
let (input, trailing_subsets) = opt(preceded(
preceded(ws_and_comments, tag(&b":>"[..])),
preceded(ws_and_comments, qualified_name),
))
.parse(input)?;
let (input, trailing_redefines) = opt(preceded(
preceded(ws_and_comments, tag(&b":>>"[..])),
preceded(ws_and_comments, qualified_name),
))
.parse(input)?;
let input = if trailing_subsets.is_some() || trailing_redefines.is_some() {
let (input, _) = preceded(ws_and_comments, tag(&b";"[..])).parse(input)?;
input
} else {
input
};
Ok((
input,
node_from_to(
start,
input,
OpaqueMemberDecl {
keyword,
name: name_str,
text: header_text.trim().to_string(),
body,
},
),
))
}
pub(crate) fn part_def(input: Input<'_>) -> IResult<Input<'_>, Node<PartDef>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, definition_prefix) = opt(alt((
map(preceded(tag(&b"abstract"[..]), ws1), |_| {
DefinitionPrefix::Abstract
}),
map(preceded(tag(&b"variation"[..]), ws1), |_| {
DefinitionPrefix::Variation
}),
)))
.parse(input)?;
let (input, is_individual) = opt(preceded(tag(&b"individual"[..]), ws1))
.parse(input)
.map(|(i, o)| (i, o.is_some()))?;
let (input, _) = tag(&b"part"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, _) = tag(&b"def"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, identification) = identification(input)?;
let before_specializes = input;
let (input, opt_specializes) = opt((
preceded(ws_and_comments, specialization_operator),
preceded(ws_and_comments, qualified_name),
))
.parse(input)?;
let (input, _) = if opt_specializes.is_some() {
many0(preceded(
preceded(ws_and_comments, tag(&b","[..])),
preceded(ws_and_comments, qualified_name),
))
.parse(input)?
} else {
(input, Vec::new())
};
let (specializes, specializes_span) = match opt_specializes {
Some((_, type_name)) => (
Some(type_name),
Some(span_from_to(before_specializes, input)),
),
None => (None, None),
};
let (input, body) = part_def_body(input)?;
Ok((
input,
node_from_to(
start,
input,
PartDef {
definition_prefix,
is_individual,
identification,
specializes,
specializes_span,
body,
},
),
))
}
pub(crate) fn part_def_or_usage(input: Input<'_>) -> IResult<Input<'_>, PartDefOrUsage> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, definition_prefix) = opt(alt((
map(preceded(tag(&b"abstract"[..]), ws1), |_| {
DefinitionPrefix::Abstract
}),
map(preceded(tag(&b"variation"[..]), ws1), |_| {
DefinitionPrefix::Variation
}),
)))
.parse(input)?;
let (input, is_individual) = opt(preceded(tag(&b"individual"[..]), ws1))
.parse(input)
.map(|(i, o)| (i, o.is_some()))?;
let (input, _) = tag(&b"part"[..]).parse(input)?;
let (input, _) = ws1(input)?;
if let Ok((input, _)) = tag::<_, _, nom::error::Error<Input>>(&b"def"[..]).parse(input) {
let (input, _) = ws1(input)?;
let (input, identification) = identification(input)?;
let before_specializes = input;
let (input, opt_specializes) = opt((
preceded(ws_and_comments, specialization_operator),
preceded(ws_and_comments, qualified_name),
))
.parse(input)?;
let (input, _) = if opt_specializes.is_some() {
many0(preceded(
preceded(ws_and_comments, tag(&b","[..])),
preceded(ws_and_comments, qualified_name),
))
.parse(input)?
} else {
(input, Vec::new())
};
let (specializes, specializes_span) = match opt_specializes {
Some((_, type_name)) => (
Some(type_name),
Some(span_from_to(before_specializes, input)),
),
None => (None, None),
};
let (input, body) = part_def_body(input)?;
return Ok((
input,
PartDefOrUsage::Def(node_from_to(
start,
input,
PartDef {
definition_prefix,
is_individual,
identification,
specializes,
specializes_span,
body,
},
)),
));
}
if let Ok((input, usage)) = part_usage_redefines_only(start, input) {
let mut usage = usage;
usage.value.is_individual = is_individual;
return Ok((input, PartDefOrUsage::Usage(usage)));
}
let (input, mut usage) = part_usage_named(start, input)?;
usage.value.is_individual = is_individual;
Ok((input, PartDefOrUsage::Usage(usage)))
}
fn multiplicity(input: Input<'_>) -> IResult<Input<'_>, String> {
let (input, _) = ws_and_comments(input)?;
let (input, _) = tag(&b"["[..]).parse(input)?;
let (input, content) = take_until(&b"]"[..]).parse(input)?;
let (input, _) = tag(&b"]"[..]).parse(input)?;
let s = format!("[{}]", String::from_utf8_lossy(content.fragment()).trim());
Ok((input, s))
}
fn usage_value_part(input: Input<'_>) -> IResult<Input<'_>, Node<crate::ast::Expression>> {
let (input, _) = ws_and_comments(input)?;
let (input, _) = alt((
preceded(tag(&b"="[..]), ws_and_comments),
preceded(tag(&b":="[..]), ws_and_comments),
preceded(
preceded(tag(&b"default"[..]), ws1),
preceded(alt((tag(&b"="[..]), tag(&b":="[..]))), ws_and_comments),
),
))
.parse(input)?;
expression(input)
}
fn part_usage_redefines_only<'a>(
start: Input<'a>,
input: Input<'a>,
) -> IResult<Input<'a>, Node<PartUsage>> {
let (input, _) = preceded(ws_and_comments, tag(&b":>>"[..])).parse(input)?;
let (input, _) = ws_and_comments(input)?;
let (input, redefines_qname) = qualified_name.parse(input)?;
let (input, multiplicity_opt) = opt(multiplicity).parse(input)?;
let (input, ordered) = opt(preceded(ws_and_comments, tag(&b"ordered"[..]))).parse(input)?;
let (input, value) = opt(preceded(ws_and_comments, usage_value_part)).parse(input)?;
let (input, _) = ws_and_comments(input)?;
let (input, _) = take_until_terminator(input, b";{")?;
let (input, body) = part_usage_body(input)?;
Ok((
input,
node_from_to(
start,
input,
PartUsage {
is_individual: false,
name: String::new(),
type_name: String::new(),
multiplicity: multiplicity_opt,
ordered: ordered.is_some(),
subsets: None,
redefines: Some(redefines_qname),
value,
body,
name_span: None,
type_ref_span: None,
},
),
))
}
fn part_usage_named<'a>(start: Input<'a>, input: Input<'a>) -> IResult<Input<'a>, Node<PartUsage>> {
let (input, _) = opt(preceded(ws_and_comments, tag(&b":>>"[..]))).parse(input)?;
let (input, _) = ws_and_comments(input)?;
let (input, (name_span, name_str)) = with_span(name).parse(input)?;
let (input, multiplicity_opt) = opt(multiplicity).parse(input)?;
let (input, type_result) = {
let (peek, _) = ws_and_comments(input)?;
if peek.fragment().starts_with(b":") && !peek.fragment().starts_with(b":>") {
let (input, _) = preceded(ws_and_comments, tag(&b":"[..])).parse(input)?;
let (input, result) =
preceded(ws_and_comments, with_span(qualified_name)).parse(input)?;
(input, Some(result))
} else {
(input, None)
}
};
let (type_ref_span, type_name) = type_result
.map(|(s, t)| (Some(s), t))
.unwrap_or((None, String::new()));
let (input, trailing_multiplicity_opt) = opt(multiplicity).parse(input)?;
let multiplicity_opt = multiplicity_opt.or(trailing_multiplicity_opt);
let (input, ordered) = opt(preceded(ws_and_comments, tag(&b"ordered"[..]))).parse(input)?;
let (input, subsets) = opt(preceded(
alt((
preceded(ws_and_comments, tag(&b":>"[..])),
preceded(ws_and_comments, tag(&b"subsets"[..])),
)),
preceded(
ws_and_comments,
(
name,
opt(preceded(
preceded(ws_and_comments, tag(&b"="[..])),
preceded(ws_and_comments, expression),
)),
),
),
))
.parse(input)?;
let (input, redefines) = opt(alt((
preceded(
preceded(ws_and_comments, tag(&b"redefines"[..])),
preceded(ws1, qualified_name),
),
preceded(
preceded(ws_and_comments, tag(&b":>>"[..])),
preceded(ws_and_comments, qualified_name),
),
)))
.parse(input)?;
let (input, value) = opt(preceded(ws_and_comments, usage_value_part)).parse(input)?;
let (input, _) = ws_and_comments(input)?;
let (input, _) = take_until_terminator(input, b";{")?;
let (input, body) = part_usage_body(input)?;
let (input, trailing_subsets) = opt(preceded(
alt((
preceded(ws_and_comments, tag(&b":>"[..])),
preceded(ws_and_comments, tag(&b"subsets"[..])),
)),
preceded(
ws_and_comments,
(
name,
opt(preceded(
preceded(ws_and_comments, tag(&b"="[..])),
preceded(ws_and_comments, expression),
)),
),
),
))
.parse(input)?;
let (input, trailing_redefines) = opt(alt((
preceded(
preceded(ws_and_comments, tag(&b"redefines"[..])),
preceded(ws1, qualified_name),
),
preceded(
preceded(ws_and_comments, tag(&b":>>"[..])),
preceded(ws_and_comments, qualified_name),
),
)))
.parse(input)?;
let subsets = subsets.or(trailing_subsets.clone());
let redefines = redefines.or(trailing_redefines.clone());
let input = if trailing_subsets.is_some() || trailing_redefines.is_some() {
let (input, _) = preceded(ws_and_comments, tag(&b";"[..])).parse(input)?;
input
} else {
input
};
Ok((
input,
node_from_to(
start,
input,
PartUsage {
is_individual: false,
name: name_str,
type_name,
multiplicity: multiplicity_opt,
ordered: ordered.is_some(),
subsets,
redefines,
value,
body,
name_span: Some(name_span),
type_ref_span,
},
),
))
}
pub(crate) fn part_usage(input: Input<'_>) -> IResult<Input<'_>, Node<PartUsage>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, is_individual) = opt(preceded(tag(&b"individual"[..]), ws1))
.parse(input)
.map(|(i, o)| (i, o.is_some()))?;
let (input, _) = tag(&b"part"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (peek, _) = ws_and_comments(input)?;
if peek.fragment().starts_with(b":")
&& !peek.fragment().starts_with(b":>")
&& !peek.fragment().starts_with(b":>>")
{
let (input, mut usage) = anonymous_part_usage(start, input)?;
usage.value.is_individual = is_individual;
return Ok((input, usage));
}
if let Ok((input, usage)) = part_usage_redefines_only(start, input) {
let mut usage = usage;
usage.value.is_individual = is_individual;
return Ok((input, usage));
}
let (input, mut usage) = part_usage_named(start, input)?;
usage.value.is_individual = is_individual;
Ok((input, usage))
}
fn anonymous_part_usage<'a>(
start: Input<'a>,
input: Input<'a>,
) -> IResult<Input<'a>, Node<PartUsage>> {
let (input, _) = preceded(ws_and_comments, tag(&b":"[..])).parse(input)?;
let (input, type_name) = preceded(ws_and_comments, qualified_name).parse(input)?;
let (input, multiplicity_opt) = opt(multiplicity).parse(input)?;
let (input, ordered) = opt(preceded(ws_and_comments, tag(&b"ordered"[..]))).parse(input)?;
let (input, subsets) = opt(preceded(
alt((
preceded(ws_and_comments, tag(&b":>"[..])),
preceded(ws_and_comments, tag(&b"subsets"[..])),
)),
preceded(
ws_and_comments,
(
name,
opt(preceded(
preceded(ws_and_comments, tag(&b"="[..])),
preceded(ws_and_comments, expression),
)),
),
),
))
.parse(input)?;
let (input, redefines) = opt(alt((
preceded(
preceded(ws_and_comments, tag(&b"redefines"[..])),
preceded(ws1, qualified_name),
),
preceded(
preceded(ws_and_comments, tag(&b":>>"[..])),
preceded(ws_and_comments, qualified_name),
),
)))
.parse(input)?;
let (input, value) = opt(preceded(ws_and_comments, usage_value_part)).parse(input)?;
let (input, _) = ws_and_comments(input)?;
let (input, _) = take_until_terminator(input, b";{")?;
let (input, body) = part_usage_body(input)?;
Ok((
input,
node_from_to(
start,
input,
PartUsage {
is_individual: false,
name: String::new(),
type_name,
multiplicity: multiplicity_opt,
ordered: ordered.is_some(),
subsets,
redefines,
value,
body,
name_span: None,
type_ref_span: None,
},
),
))
}
fn part_usage_body(input: Input<'_>) -> IResult<Input<'_>, PartUsageBody> {
let (input, _) = ws_and_comments(input)?;
let frag = input.fragment();
log::debug!(
"part_usage_body: first 40 bytes: {:?}",
frag.get(..40.min(frag.len())).unwrap_or(frag),
);
let result = alt((
map(tag(&b";"[..]), |_| PartUsageBody::Semicolon),
part_usage_body_brace,
))
.parse(input);
if result.is_err() {
log::debug!(
"part_usage_body: failed at: {:?}",
String::from_utf8_lossy(frag.get(..60.min(frag.len())).unwrap_or(frag)),
);
}
result
}
fn part_usage_body_brace(input: Input<'_>) -> IResult<Input<'_>, PartUsageBody> {
let (mut input, _) = tag(&b"{"[..]).parse(input)?;
let mut elements = Vec::new();
loop {
let (next, _) = ws_and_comments(input)?;
input = next;
if input.fragment().is_empty() {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Eof,
)));
}
if input.fragment().starts_with(b"}") {
let (input, _) = preceded(ws_and_comments, tag(&b"}"[..])).parse(input)?;
log::debug!("part_usage_body: brace ok, {} elements", elements.len());
return Ok((input, PartUsageBody::Brace { elements }));
}
match part_usage_body_element(input) {
Ok((next, element)) => {
if next.location_offset() == input.location_offset() {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Many0,
)));
}
elements.push(element);
input = next;
}
Err(_) if starts_with_any_keyword(input.fragment(), PART_BODY_STARTERS) => {
let (next, _) = recover_body_element(input, PART_BODY_STARTERS)?;
if next.location_offset() == input.location_offset() {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Many0,
)));
}
elements.push(node_from_to(
input,
next,
PartUsageBodyElement::Error(Node::new(
crate::ast::Span::dummy(),
build_recovery_error_node_from_span(
input,
next,
PART_BODY_STARTERS,
"part usage body",
"recovered_part_usage_body_element",
),
)),
));
input = next;
}
Err(_) => {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Tag,
)));
}
}
}
}
fn perform_action_path(input: Input<'_>) -> IResult<Input<'_>, String> {
let (input, first) = name(input)?;
let mut rest_parser = many0(preceded(
preceded(ws_and_comments, tag(&b"."[..])),
preceded(ws_and_comments, name),
));
let (input, rest) = rest_parser.parse(input)?;
let action_name = std::iter::once(first)
.chain(rest)
.collect::<Vec<_>>()
.join(".");
Ok((input, action_name))
}
fn perform_in_out_binding(input: Input<'_>) -> IResult<Input<'_>, Node<PerformInOutBinding>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, direction) = alt((
value(InOut::In, tag(&b"in"[..])),
value(InOut::Out, tag(&b"out"[..])),
))
.parse(input)?;
let (input, _) = ws1(input)?;
let (input, name_str) = name(input)?;
let (input, _) = preceded(ws_and_comments, tag(&b"="[..])).parse(input)?;
let (input, value_expr) = preceded(ws_and_comments, path_expression).parse(input)?;
let (input, _) = preceded(ws_and_comments, tag(&b";"[..])).parse(input)?;
Ok((
input,
node_from_to(
start,
input,
PerformInOutBinding {
direction,
name: name_str,
value: value_expr,
},
),
))
}
fn perform_body_element(input: Input<'_>) -> IResult<Input<'_>, Node<PerformBodyElement>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, elem) = alt((
map(doc_comment, PerformBodyElement::Doc),
map(perform_in_out_binding, PerformBodyElement::InOut),
))
.parse(input)?;
Ok((input, node_from_to(start, input, elem)))
}
fn perform_body(input: Input<'_>) -> IResult<Input<'_>, PerformBody> {
let (input, _) = ws_and_comments(input)?;
let (input, elements) = nom::sequence::delimited(
tag(&b"{"[..]),
preceded(
ws_and_comments,
many0(preceded(ws_and_comments, perform_body_element)),
),
preceded(ws_and_comments, tag(&b"}"[..])),
)
.parse(input)?;
Ok((input, PerformBody::Brace { elements }))
}
fn perform_usage(input: Input<'_>) -> IResult<Input<'_>, Node<Perform>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, _) = tag(&b"perform"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, action_name) = perform_action_path(input)?;
let (input, body) = perform_body(input)?;
Ok((
input,
node_from_to(
start,
input,
Perform {
action_name,
type_name: None,
body,
},
),
))
}
pub(crate) fn perform_action_decl(input: Input<'_>) -> IResult<Input<'_>, Node<Perform>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, _) = tag(&b"perform"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, _) = tag(&b"action"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, action_name) = name(input)?;
let (input, type_name) = opt(preceded(
preceded(ws_and_comments, tag(&b":"[..])),
preceded(ws_and_comments, qualified_name),
))
.parse(input)?;
let (input, body) = preceded(
ws_and_comments,
alt((
map(tag(&b";"[..]), |_| PerformBody::Semicolon),
perform_body,
)),
)
.parse(input)?;
Ok((
input,
node_from_to(
start,
input,
Perform {
action_name,
type_name,
body,
},
),
))
}
fn allocate_(input: Input<'_>) -> IResult<Input<'_>, Node<Allocate>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, _) = tag(&b"allocate"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, source) = path_expression(input)?;
let (input, _) = preceded(ws_and_comments, tag(&b"to"[..])).parse(input)?;
let (input, target) = preceded(ws_and_comments, path_expression).parse(input)?;
let (input, body) = connect_body(input)?;
Ok((
input,
node_from_to(
start,
input,
Allocate {
source,
target,
body,
},
),
))
}
pub(crate) fn bind_(input: Input<'_>) -> IResult<Input<'_>, Node<Bind>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, _) = tag(&b"bind"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, left) = path_expression(input)?;
let (input, _) = preceded(ws_and_comments, tag(&b"="[..])).parse(input)?;
let (input, right) = preceded(ws_and_comments, path_expression).parse(input)?;
let mut body_parser = alt((
map(preceded(ws_and_comments, tag(&b";"[..])), |_| {
Some(ConnectBody::Semicolon)
}),
map(
nom::sequence::delimited(
preceded(ws_and_comments, tag(&b"{"[..])),
skip_until_brace_end,
preceded(ws_and_comments, tag(&b"}"[..])),
),
|_| Some(ConnectBody::Brace),
),
));
let (input, body) = body_parser.parse(input)?;
Ok((
input,
node_from_to(start, input, Bind { left, right, body }),
))
}
fn connect_(input: Input<'_>) -> IResult<Input<'_>, Node<Connect>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, _) = tag(&b"connect"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, from_expr) = path_expression(input)?;
let (input, _) = preceded(ws_and_comments, tag(&b"to"[..])).parse(input)?;
let (input, to_expr) = preceded(ws_and_comments, path_expression).parse(input)?;
let (input, body) = connect_body(input)?;
let (input, trailing_subsets) = opt(preceded(
preceded(ws_and_comments, tag(&b":>"[..])),
preceded(ws_and_comments, qualified_name),
))
.parse(input)?;
let (input, trailing_redefines) = opt(preceded(
preceded(ws_and_comments, tag(&b":>>"[..])),
preceded(ws_and_comments, qualified_name),
))
.parse(input)?;
let input = if trailing_subsets.is_some() || trailing_redefines.is_some() {
let (input, _) = preceded(ws_and_comments, tag(&b";"[..])).parse(input)?;
input
} else {
input
};
Ok((
input,
node_from_to(
start,
input,
Connect {
from: from_expr,
to: to_expr,
body,
},
),
))
}
fn interface_usage_body_element(
input: Input<'_>,
) -> IResult<Input<'_>, Node<InterfaceUsageBodyElement>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, _) = tag(&b"ref"[..]).parse(input)?;
let (input, _) = preceded(ws_and_comments, tag(&b":>>"[..])).parse(input)?;
let (input, ref_name) = preceded(ws_and_comments, name).parse(input)?;
let (input, _) = preceded(ws_and_comments, tag(&b"="[..])).parse(input)?;
let (input, value) = preceded(ws_and_comments, expression).parse(input)?;
let (input, body) = ref_body_parse(input)?;
Ok((
input,
node_from_to(
start,
input,
InterfaceUsageBodyElement::RefRedef {
name: ref_name,
value,
body,
},
),
))
}
fn ref_body_parse(input: Input<'_>) -> IResult<Input<'_>, RefBody> {
let (input, _) = ws_and_comments(input)?;
alt((
map(tag(&b";"[..]), |_| RefBody::Semicolon),
map(
nom::sequence::delimited(
tag(&b"{"[..]),
skip_until_brace_end,
preceded(ws_and_comments, tag(&b"}"[..])),
),
|_| RefBody::Brace,
),
))
.parse(input)
}
fn connect_body_with_elements(
input: Input<'_>,
) -> IResult<Input<'_>, (ConnectBody, Vec<Node<InterfaceUsageBodyElement>>)> {
let (input, _) = ws_and_comments(input)?;
if let Ok((input, _)) = tag::<_, _, nom::error::Error<Input>>(&b";"[..]).parse(input) {
return Ok((input, (ConnectBody::Semicolon, vec![])));
}
let (mut input, _) = tag(&b"{"[..]).parse(input)?;
let mut elements = Vec::new();
loop {
let (next, _) = ws_and_comments(input)?;
input = next;
if input.fragment().starts_with(b"}") {
let (input, _) = tag(&b"}"[..]).parse(input)?;
return Ok((input, (ConnectBody::Brace, elements)));
}
let (next, element) = interface_usage_body_element(input)?;
if next.location_offset() == input.location_offset() {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Many0,
)));
}
elements.push(element);
input = next;
}
}
fn connector_end_expression(input: Input<'_>) -> IResult<Input<'_>, Node<Expression>> {
let (input, _) = ws_and_comments(input)?;
let (input, _) = opt((name, preceded(ws_and_comments, tag(&b"::>"[..])))).parse(input)?;
preceded(ws_and_comments, path_expression).parse(input)
}
fn interface_usage(input: Input<'_>) -> IResult<Input<'_>, Node<InterfaceUsage>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, _) = tag(&b"interface"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, named_interface) = opt((
name,
opt(multiplicity),
preceded(ws_and_comments, tag(&b":"[..])),
preceded(ws_and_comments, qualified_name),
))
.parse(input)?;
let (input, interface_type) = if let Some((_, _, _, interface_type)) = named_interface {
(input, Some(interface_type))
} else {
opt(preceded(
tag(&b":"[..]),
preceded(ws_and_comments, qualified_name),
))
.parse(input)?
};
let (input, _) = ws_and_comments(input)?;
if input.fragment().starts_with(b"connect") {
let (input, _) = tag(&b"connect"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, from_expr) = connector_end_expression(input)?;
let (input, _) = preceded(ws_and_comments, tag(&b"to"[..])).parse(input)?;
let (input, to_expr) = preceded(ws_and_comments, connector_end_expression).parse(input)?;
let (input, (body, body_elements)) = connect_body_with_elements(input)?;
Ok((
input,
node_from_to(
start,
input,
InterfaceUsage::TypedConnect {
interface_type,
from: from_expr,
to: to_expr,
body,
body_elements,
},
),
))
} else {
let (input, from_expr) = connector_end_expression(input)?;
let (input, _) = preceded(ws_and_comments, tag(&b"to"[..])).parse(input)?;
let (input, to_expr) = preceded(ws_and_comments, connector_end_expression).parse(input)?;
let (input, _) = opt(connect_body).parse(input)?;
Ok((
input,
node_from_to(
start,
input,
InterfaceUsage::Connection {
from: from_expr,
to: to_expr,
body_elements: vec![],
},
),
))
}
}
fn part_ref_usage(input: Input<'_>) -> IResult<Input<'_>, Node<RefDecl>> {
let start = input;
let (input, _) = tag(&b"ref"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, name_str) = name(input)?;
let (input, _) = preceded(ws_and_comments, tag(&b":"[..])).parse(input)?;
let (input, type_name) = preceded(ws_and_comments, qualified_name).parse(input)?;
let (input, value) = opt(preceded(
preceded(ws_and_comments, tag(&b"="[..])),
preceded(ws_and_comments, expression),
))
.parse(input)?;
let (input, body) = preceded(
ws_and_comments,
alt((
map(tag(&b";"[..]), |_| RefBody::Semicolon),
map(
delimited(
tag(&b"{"[..]),
skip_until_brace_end,
preceded(ws_and_comments, tag(&b"}"[..])),
),
|_| RefBody::Brace,
),
)),
)
.parse(input)?;
Ok((
input,
node_from_to(
start,
input,
RefDecl {
name: name_str,
type_name,
value,
body,
name_span: None,
type_ref_span: None,
},
),
))
}
fn part_usage_body_element(input: Input<'_>) -> IResult<Input<'_>, Node<PartUsageBodyElement>> {
let (input, _) = ws_and_comments(input)?;
let start = input;
let frag = start.fragment();
let first_30 = frag.get(..30.min(frag.len())).unwrap_or(frag);
log::debug!(
"part_usage_body_element: first 30 bytes: {:?} (str: {:?})",
first_30,
String::from_utf8_lossy(first_30),
);
let (input, elem) = alt((
map(doc_comment, PartUsageBodyElement::Doc),
map(annotation, PartUsageBodyElement::Annotation),
map(
metadata_annotation,
PartUsageBodyElement::MetadataAnnotation,
),
map(
exhibit_state_as_state_usage,
PartUsageBodyElement::StateUsage,
),
map(perform_action_decl, PartUsageBodyElement::Perform),
map(perform_usage, PartUsageBodyElement::Perform),
map(allocate_, PartUsageBodyElement::Allocate),
map(attribute_usage, PartUsageBodyElement::AttributeUsage),
map(
attribute_usage_shorthand,
PartUsageBodyElement::AttributeUsage,
),
map(part_usage, |p| PartUsageBodyElement::PartUsage(Box::new(p))),
map(individual_usage, |n| {
PartUsageBodyElement::OccurrenceUsage(Box::new(n))
}),
map(snapshot_usage, |n| {
PartUsageBodyElement::OccurrenceUsage(Box::new(n))
}),
map(timeslice_usage, |n| {
PartUsageBodyElement::OccurrenceUsage(Box::new(n))
}),
map(then_timeslice_usage, |n| {
PartUsageBodyElement::OccurrenceUsage(Box::new(n))
}),
map(occurrence_usage, |n| {
PartUsageBodyElement::OccurrenceUsage(Box::new(n))
}),
map(port_usage, PartUsageBodyElement::PortUsage),
map(part_ref_usage, PartUsageBodyElement::Ref),
map(bind_, PartUsageBodyElement::Bind),
map(satisfy, PartUsageBodyElement::Satisfy),
map(interface_usage, PartUsageBodyElement::InterfaceUsage),
map(connect_, PartUsageBodyElement::Connect),
))
.parse(input)?;
Ok((input, node_from_to(start, input, elem)))
}
fn exhibit_state_as_state_usage(
input: Input<'_>,
) -> IResult<Input<'_>, Node<crate::ast::StateUsage>> {
let (input, exhibit) = exhibit_state(input)?;
let state = crate::ast::StateUsage {
name: exhibit.value.name,
type_name: exhibit.value.type_name,
body: exhibit.value.body,
};
Ok((input, Node::new(exhibit.span, state)))
}