1use pest::{Parser, error::Error, iterators::Pair};
2
3use crate::synapse::{Rule, SynapseParser};
4
5use super::*;
6
7pub fn parse(input: &str) -> Result<SynFile, Error<Rule>> {
10 let file_pair = SynapseParser::parse(Rule::file, input)?.next().unwrap();
11 Ok(build_file(file_pair))
12}
13
14fn build_file(pair: Pair<Rule>) -> SynFile {
17 let items = pair
18 .into_inner()
19 .filter_map(|p| match p.as_rule() {
20 Rule::namespace_decl => Some(Item::Namespace(build_namespace(p))),
21 Rule::import_decl => Some(Item::Import(build_import(p))),
22 Rule::const_decl => Some(Item::Const(build_const(p))),
23 Rule::enum_def => Some(Item::Enum(build_enum(p))),
24 Rule::struct_def => Some(Item::Struct(build_struct(p))),
25 Rule::table_def => Some(Item::Table(build_struct(p))),
26 Rule::command_def => Some(Item::Command(build_packet(p, PacketKind::Command))),
27 Rule::telemetry_def => Some(Item::Telemetry(build_packet(p, PacketKind::Telemetry))),
28 Rule::message_def => Some(Item::Message(build_packet(p, PacketKind::Message))),
29 Rule::EOI => None,
30 r => unreachable!("unexpected rule: {:?}", r),
31 })
32 .collect();
33 SynFile { items }
34}
35
36fn build_namespace(pair: Pair<Rule>) -> NamespaceDecl {
37 let scoped = pair.into_inner().next().unwrap();
38 NamespaceDecl {
39 name: build_scoped_ident(scoped),
40 }
41}
42
43fn build_import(pair: Pair<Rule>) -> ImportDecl {
44 let s = pair.into_inner().next().unwrap().as_str();
45 ImportDecl {
46 path: s[1..s.len() - 1].to_string(),
47 }
48}
49
50fn build_const(pair: Pair<Rule>) -> ConstDecl {
51 let mut inner = pair.into_inner().peekable();
52 let doc = extract_doc(&mut inner);
53 let attrs = extract_attrs(&mut inner);
54 let name = inner.next().unwrap().as_str().to_string();
55 let ty = build_type_expr(inner.next().unwrap());
56 let value = build_literal(inner.next().unwrap());
57 ConstDecl {
58 name,
59 ty,
60 value,
61 doc,
62 attrs,
63 }
64}
65
66fn build_enum(pair: Pair<Rule>) -> EnumDef {
67 let mut inner = pair.into_inner().peekable();
68 let doc = extract_doc(&mut inner);
69 let attrs = extract_attrs(&mut inner);
70 let first = inner.next().unwrap();
71 let (repr, name) = if first.as_rule() == Rule::primitive_type {
72 let repr = build_primitive_type(first);
73 (Some(repr), inner.next().unwrap().as_str().to_string())
74 } else {
75 (None, first.as_str().to_string())
76 };
77 let variants = inner.map(build_enum_variant).collect();
78 EnumDef {
79 name,
80 repr,
81 variants,
82 doc,
83 attrs,
84 }
85}
86
87fn build_enum_variant(pair: Pair<Rule>) -> EnumVariant {
88 let mut inner = pair.into_inner().peekable();
89 let doc = extract_doc(&mut inner);
90 let name = inner.next().unwrap().as_str().to_string();
91 let value = inner.next().map(|p| p.as_str().parse::<i64>().unwrap());
92 EnumVariant { name, value, doc }
93}
94
95fn build_struct(pair: Pair<Rule>) -> StructDef {
96 let mut inner = pair.into_inner().peekable();
97 let doc = extract_doc(&mut inner);
98 let attrs = extract_attrs(&mut inner);
99 let name = inner.next().unwrap().as_str().to_string();
100 let fields = inner.map(build_field).collect();
101 StructDef {
102 name,
103 fields,
104 doc,
105 attrs,
106 }
107}
108
109fn build_packet(pair: Pair<Rule>, kind: PacketKind) -> MessageDef {
110 let mut inner = pair.into_inner().peekable();
111 let doc = extract_doc(&mut inner);
112 let attrs = extract_attrs(&mut inner);
113 let name = inner.next().unwrap().as_str().to_string();
114 let fields = inner.map(build_field).collect();
115 MessageDef {
116 kind,
117 name,
118 fields,
119 doc,
120 attrs,
121 }
122}
123
124fn build_field(pair: Pair<Rule>) -> FieldDef {
125 let mut inner = pair.into_inner().peekable();
126 let doc = extract_doc(&mut inner);
127 let name = inner.next().unwrap().as_str().to_string();
128
129 let next = inner.next().unwrap();
130 let (optional, type_pair) = if next.as_rule() == Rule::optional_marker {
131 (true, inner.next().unwrap())
132 } else {
133 (false, next)
134 };
135
136 let ty = build_type_expr(type_pair);
137 let default = inner.next().map(build_literal);
138
139 FieldDef {
140 name,
141 optional,
142 ty,
143 default,
144 doc,
145 }
146}
147
148fn extract_doc<'i>(
150 inner: &mut std::iter::Peekable<impl Iterator<Item = Pair<'i, Rule>>>,
151) -> Vec<String> {
152 if inner.peek().map(|p| p.as_rule()) == Some(Rule::doc_block) {
153 inner
154 .next()
155 .unwrap()
156 .into_inner()
157 .map(|p| {
158 p.as_str()
159 .strip_prefix("///")
160 .unwrap_or("")
161 .trim()
162 .to_string()
163 })
164 .collect()
165 } else {
166 vec![]
167 }
168}
169
170fn extract_attrs<'i>(
172 inner: &mut std::iter::Peekable<impl Iterator<Item = Pair<'i, Rule>>>,
173) -> Vec<Attribute> {
174 let mut attrs = vec![];
175 while inner.peek().map(|p| p.as_rule()) == Some(Rule::attribute) {
176 let attr = inner.next().unwrap();
177 let mut ai = attr.into_inner();
178 let name = ai.next().unwrap().as_str().to_string();
179 let value = build_literal(ai.next().unwrap());
180 attrs.push(Attribute { name, value });
181 }
182 attrs
183}
184
185fn build_type_expr(pair: Pair<Rule>) -> TypeExpr {
186 let mut inner = pair.into_inner();
187 let base = build_base_type(inner.next().unwrap());
188 let array = inner.next().map(build_array_suffix);
189 TypeExpr { base, array }
190}
191
192fn build_base_type(pair: Pair<Rule>) -> BaseType {
193 let inner = pair.into_inner().next().unwrap();
194 match inner.as_rule() {
195 Rule::string_type => BaseType::String,
196 Rule::primitive_type => BaseType::Primitive(build_primitive_type(inner)),
197 Rule::type_ref => BaseType::Ref(build_scoped_ident(inner.into_inner().next().unwrap())),
198 r => unreachable!("unexpected base_type rule: {:?}", r),
199 }
200}
201
202fn build_primitive_type(pair: Pair<Rule>) -> PrimitiveType {
203 match pair.as_str() {
204 "f32" => PrimitiveType::F32,
205 "f64" => PrimitiveType::F64,
206 "i8" => PrimitiveType::I8,
207 "i16" => PrimitiveType::I16,
208 "i32" => PrimitiveType::I32,
209 "i64" => PrimitiveType::I64,
210 "u8" => PrimitiveType::U8,
211 "u16" => PrimitiveType::U16,
212 "u32" => PrimitiveType::U32,
213 "u64" => PrimitiveType::U64,
214 "bool" => PrimitiveType::Bool,
215 "bytes" => PrimitiveType::Bytes,
216 s => unreachable!("unknown primitive: {}", s),
217 }
218}
219
220fn build_array_suffix(pair: Pair<Rule>) -> ArraySuffix {
221 match pair.into_inner().next() {
222 None => ArraySuffix::Dynamic,
223 Some(p) => {
224 let inner = p.into_inner().next().unwrap();
225 match inner.as_rule() {
226 Rule::bounded_size => {
227 let n = inner
228 .into_inner()
229 .next()
230 .unwrap()
231 .as_str()
232 .parse::<u64>()
233 .unwrap();
234 ArraySuffix::Bounded(n)
235 }
236 Rule::pos_int => ArraySuffix::Fixed(inner.as_str().parse::<u64>().unwrap()),
237 r => unreachable!("unexpected array_size rule: {:?}", r),
238 }
239 }
240 }
241}
242
243fn build_literal(pair: Pair<Rule>) -> Literal {
244 let inner = pair.into_inner().next().unwrap();
245 match inner.as_rule() {
246 Rule::float_lit => Literal::Float(inner.as_str().parse::<f64>().unwrap()),
247 Rule::hex_lit => {
248 let s = inner.as_str();
249 let digits = &s[2..]; Literal::Hex(u64::from_str_radix(digits, 16).unwrap())
251 }
252 Rule::int_lit => Literal::Int(inner.as_str().parse::<i64>().unwrap()),
253 Rule::bool_lit => Literal::Bool(inner.as_str() == "true"),
254 Rule::string_lit => {
255 let s = inner.as_str();
256 Literal::Str(unescape(&s[1..s.len() - 1]))
257 }
258 Rule::ident_lit => Literal::Ident(build_scoped_ident(inner.into_inner().next().unwrap())),
259 r => unreachable!("unexpected literal rule: {:?}", r),
260 }
261}
262
263fn build_scoped_ident(pair: Pair<Rule>) -> ScopedIdent {
264 pair.into_inner().map(|p| p.as_str().to_string()).collect()
265}
266
267fn unescape(s: &str) -> String {
268 let mut out = String::with_capacity(s.len());
269 let mut chars = s.chars();
270 while let Some(c) = chars.next() {
271 if c == '\\' {
272 match chars.next() {
273 Some('n') => out.push('\n'),
274 Some('t') => out.push('\t'),
275 Some('r') => out.push('\r'),
276 Some('\\') => out.push('\\'),
277 Some('"') => out.push('"'),
278 Some(c) => {
279 out.push('\\');
280 out.push(c);
281 }
282 None => out.push('\\'),
283 }
284 } else {
285 out.push(c);
286 }
287 }
288 out
289}