#![allow(dead_code, unused_imports)]
use crate::ast::{
ConnectStmt, ConnectionDef, ConnectionDefBody, ConnectionDefBodyElement, EndDecl, Node,
RefBody, RefDecl,
};
use crate::parser::expr::path_expression;
use crate::parser::lex::{
identification, name, qualified_name, recover_body_element, skip_until_brace_end,
starts_with_any_keyword, take_until_terminator, ws1, ws_and_comments,
CONNECTION_DEF_BODY_STARTERS,
};
use crate::parser::node_from_to;
use crate::parser::with_span;
use crate::parser::Input;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::combinator::map;
use nom::multi::many0;
use nom::sequence::preceded;
use nom::IResult;
use nom::Parser;
fn end_decl(input: Input<'_>) -> IResult<Input<'_>, Node<EndDecl>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, _) = tag(&b"end"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, (name_span, name_str)) = with_span(name).parse(input)?;
let (input, _) = preceded(ws_and_comments, tag(&b":"[..])).parse(input)?;
let (input, (type_ref_span, type_name)) =
preceded(ws_and_comments, with_span(qualified_name)).parse(input)?;
let (input, _) = preceded(ws_and_comments, tag(&b";"[..])).parse(input)?;
Ok((
input,
node_from_to(
start,
input,
EndDecl {
name: name_str,
type_name,
name_span: Some(name_span),
type_ref_span: Some(type_ref_span),
},
),
))
}
fn ref_body(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 ref_decl(input: Input<'_>) -> IResult<Input<'_>, Node<RefDecl>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, _) = tag(&b"ref"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, (name_span, name_str)) = with_span(name).parse(input)?;
let (input, _) = preceded(ws_and_comments, tag(&b":"[..])).parse(input)?;
let (input, (type_ref_span, type_name)) =
preceded(ws_and_comments, with_span(qualified_name)).parse(input)?;
let (input, body) = ref_body(input)?;
Ok((
input,
node_from_to(
start,
input,
RefDecl {
name: name_str,
type_name,
value: None,
body,
name_span: Some(name_span),
type_ref_span: Some(type_ref_span),
},
),
))
}
fn connect_body(input: Input<'_>) -> IResult<Input<'_>, crate::ast::ConnectBody> {
let (input, _) = ws_and_comments(input)?;
alt((
map(tag(&b";"[..]), |_| crate::ast::ConnectBody::Semicolon),
map(
nom::sequence::delimited(
tag(&b"{"[..]),
skip_until_brace_end,
preceded(ws_and_comments, tag(&b"}"[..])),
),
|_| crate::ast::ConnectBody::Brace,
),
))
.parse(input)
}
fn connect_stmt(input: Input<'_>) -> IResult<Input<'_>, Node<ConnectStmt>> {
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)?;
Ok((
input,
node_from_to(
start,
input,
ConnectStmt {
from: from_expr,
to: to_expr,
body,
},
),
))
}
fn connection_def_body_element(
input: Input<'_>,
) -> IResult<Input<'_>, Node<ConnectionDefBodyElement>> {
let (input, _) = ws_and_comments(input)?;
let start = input;
let (input, elem) = alt((
map(end_decl, ConnectionDefBodyElement::EndDecl),
map(ref_decl, ConnectionDefBodyElement::RefDecl),
map(connect_stmt, ConnectionDefBodyElement::ConnectStmt),
))
.parse(input)?;
Ok((input, node_from_to(start, input, elem)))
}
fn connection_def_body(input: Input<'_>) -> IResult<Input<'_>, ConnectionDefBody> {
let (mut input, _) = ws_and_comments(input)?;
if input.fragment().starts_with(b";") {
let (input, _) = tag(&b";"[..]).parse(input)?;
return Ok((input, ConnectionDefBody::Semicolon));
}
let (next, _) = tag(&b"{"[..]).parse(input)?;
input = next;
let mut elements = Vec::new();
loop {
let (next, _) = ws_and_comments(input)?;
input = next;
if input.fragment().starts_with(b"}") {
let (input, _) = preceded(ws_and_comments, tag(&b"}"[..])).parse(input)?;
return Ok((input, ConnectionDefBody::Brace { elements }));
}
match connection_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(), CONNECTION_DEF_BODY_STARTERS) => {
let (next, _) = recover_body_element(input, CONNECTION_DEF_BODY_STARTERS)?;
if next.location_offset() == input.location_offset() {
return Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::Many0,
)));
}
input = next;
}
Err(_) => {
let (input, _) = skip_until_brace_end(input)?;
let (input, _) = preceded(ws_and_comments, tag(&b"}"[..])).parse(input)?;
return Ok((input, ConnectionDefBody::Brace { elements }));
}
}
}
}
pub(crate) fn connection_def(input: Input<'_>) -> IResult<Input<'_>, Node<ConnectionDef>> {
let start = input;
let (input, _) = ws_and_comments(input)?;
let (input, _) = nom::combinator::opt(preceded(tag(&b"abstract"[..]), ws1)).parse(input)?;
let (input, _) = tag(&b"connection"[..]).parse(input)?;
let (input, _) = ws1(input)?;
let (input, _) = nom::combinator::opt(preceded(tag(&b"def"[..]), ws1)).parse(input)?;
let (input, identification) = identification(input)?;
let (input, _) = ws_and_comments(input)?;
let (input, _) = take_until_terminator(input, b";{")?;
let (input, body) = connection_def_body(input)?;
Ok((
input,
node_from_to(
start,
input,
ConnectionDef {
identification,
body,
},
),
))
}