1use super::lexer::*;
4use crate::{
5 prelude::{vec, String, Vec},
6 ParsedAttribute, ParsedBlock, ParsedImport, ParsedMember, ParsedModel, ParsedPackage,
7 ParsedPort, Span, SyntaxResult,
8};
9use nom::{
10 branch::alt,
11 bytes::complete::{tag, take_while},
12 character::complete::{char, multispace0, multispace1},
13 combinator::{map, opt},
14 error::context,
15 multi::many0,
16 sequence::{delimited, preceded, terminated},
17};
18use sysml_model::QualifiedName;
19
20pub fn model<'a>(input: impl Into<Span<'a>>) -> SyntaxResult<'a, (Span<'a>, ParsedModel)> {
21 let (input, package) =
22 context("model", delimited(multispace0, package, multispace0))(input.into())?;
23
24 Ok((
25 input,
26 ParsedModel {
27 members: vec![ParsedMember::Package(package)],
28 },
29 ))
30}
31
32pub fn members<'a>(input: impl Into<Span<'a>>) -> SyntaxResult<'a, (Span<'a>, Vec<ParsedMember>)> {
33 let (input, members) = context(
34 "tokens",
35 many0(alt((
36 terminated(map(import, ParsedMember::Import), multispace0),
37 terminated(map(package, ParsedMember::Package), multispace0),
38 terminated(map(block_usage, ParsedMember::BlockUsage), multispace0),
39 terminated(
40 map(attribute_usage, ParsedMember::AttributeUsage),
41 multispace0,
42 ),
43 terminated(map(port_usage, ParsedMember::PortUsage), multispace0),
44 ))),
45 )(input.into())?;
46
47 Ok((input, members))
48}
49
50pub fn import<'a>(input: impl Into<Span<'a>>) -> SyntaxResult<'a, (Span<'a>, ParsedImport)> {
51 use nom::AsChar;
52 let (input, _) = tag("import")(input.into())?;
53 let (input, _) = multispace1(input)?;
54 let (input, name) = map(take_while(|c| AsChar::as_char(c) != ';'), |span: Span| {
55 QualifiedName::from(span.into_fragment())
56 })(input)?;
57 let (input, _) = char(';')(input)?;
58
59 Ok((input, ParsedImport::new(name)))
60}
61
62pub fn package<'a>(input: impl Into<Span<'a>>) -> SyntaxResult<'a, (Span<'a>, ParsedPackage)> {
63 let (input, (name, short_name, _, members)) = element(input.into(), "package")?;
64
65 Ok((
66 input,
67 ParsedPackage {
68 name: name.map(String::from),
69 short_name: short_name.map(String::from),
70 members,
71 },
72 ))
73}
74
75pub fn block_usage<'a>(input: impl Into<Span<'a>>) -> SyntaxResult<'a, (Span<'a>, ParsedBlock)> {
76 let (input, (name, short_name, definition, members)) = element(input.into(), "block")?;
77
78 Ok((
79 input,
80 ParsedBlock {
81 name,
82 short_name,
83 definition,
84 members,
85 },
86 ))
87}
88
89pub fn attribute_usage<'a>(
90 input: impl Into<Span<'a>>,
91) -> SyntaxResult<'a, (Span<'a>, ParsedAttribute)> {
92 let (input, (name, short_name, definition, members)) = element(input.into(), "attribute")?;
93
94 Ok((
95 input,
96 ParsedAttribute {
97 name,
98 short_name,
99 definition,
100 members,
101 },
102 ))
103}
104
105pub fn port_usage<'a>(input: impl Into<Span<'a>>) -> SyntaxResult<'a, (Span<'a>, ParsedPort)> {
106 let (input, (name, short_name, definition, members)) = element(input.into(), "port")?;
107
108 Ok((
109 input,
110 ParsedPort {
111 name,
112 short_name,
113 definition,
114 members,
115 },
116 ))
117}
118
119pub fn element<'a>(
120 input: impl Into<Span<'a>>,
121 tag_name: &'static str,
122) -> SyntaxResult<
123 'a,
124 (
125 Span<'a>,
126 (
127 Option<String>,
128 Option<String>,
129 Option<QualifiedName>,
130 Vec<ParsedMember>,
131 ),
132 ),
133> {
134 let (input, _) = context(tag_name, tag(tag_name))(input.into())?;
135 let (input, _) = multispace1(input)?;
136 let (input, (name, short_name)) = identification(input)?;
137 let (input, _) = multispace0(input)?;
138 let (input, definition) = opt(delimited(
139 terminated(char(':'), multispace0),
140 qualified_name,
141 multispace0,
142 ))(input)?;
143 let (input, members) = alt((
144 map(char(';'), |_| Vec::new()),
145 delimited(
146 char('{'),
147 preceded(multispace0, members),
148 preceded(multispace0, char('}')),
149 ),
150 ))(input)?;
151
152 Ok((input, (name, short_name, definition, members)))
153}
154
155pub fn identification<'a>(
156 input: impl Into<Span<'a>>,
157) -> SyntaxResult<'a, (Span<'a>, (Option<String>, Option<String>))> {
158 let (input, short_name) = opt(delimited(char('<'), name, char('>')))(input.into())?;
159 let (input, _) = multispace0(input)?;
160 let (input, name) = opt(name)(input)?;
161
162 Ok((input, (name, short_name)))
163}
164
165#[cfg(test)]
166mod tests {}