dialectic_compiler/
parse.rs1use {
4 proc_macro2::Span,
5 syn::{
6 braced,
7 parse::{Error, Parse, ParseStream, Result},
8 spanned::Spanned as SpannedExt,
9 token, Lifetime, LitInt, Token, Type,
10 },
11};
12
13use crate::{
14 syntax::{Invocation, Syntax},
15 Spanned,
16};
17
18mod kw {
19 use super::*;
20
21 syn::custom_keyword!(recv);
22 syn::custom_keyword!(send);
23 syn::custom_keyword!(call);
24 syn::custom_keyword!(choose);
25 syn::custom_keyword!(offer);
26 syn::custom_keyword!(split);
27
28 pub fn peek_any(input: ParseStream) -> bool {
30 input.peek(recv)
31 || input.peek(send)
32 || input.peek(call)
33 || input.peek(choose)
34 || input.peek(offer)
35 || input.peek(split)
36 }
37}
38
39impl Parse for Invocation {
40 fn parse(input: ParseStream) -> Result<Self> {
41 let mut nodes = Vec::new();
42 while !input.is_empty() {
43 let terminator_required = requires_terminator(&input);
44 nodes.push(input.parse::<Spanned<Syntax>>()?);
45
46 if !input.is_empty() && (terminator_required || input.peek(Token![;])) {
47 input.parse::<Token![;]>()?;
48 }
49 }
50
51 let ast = Spanned {
52 inner: Syntax::Block(nodes),
53 span: Span::call_site(),
54 };
55 Ok(Invocation { syntax: ast })
56 }
57}
58
59#[derive(Clone, Copy, PartialEq)]
61enum Direction {
62 Transmit,
64 Receive,
66}
67
68struct SplitArm {
71 dir: Direction,
73 body: Spanned<Syntax>,
75}
76
77impl Parse for SplitArm {
78 fn parse(input: ParseStream) -> Result<Self> {
79 let lookahead = input.lookahead1();
80 let dir = if lookahead.peek(Token![->]) {
81 let _ = input.parse::<Token![->]>()?;
82 Direction::Transmit
83 } else if lookahead.peek(Token![<-]) {
84 let _ = input.parse::<Token![<-]>()?;
85 Direction::Receive
86 } else {
87 return Err(lookahead.error());
88 };
89 let terminator_required = requires_terminator(&input);
90 let arm = input.parse::<Spanned<Syntax>>()?;
91 if !input.is_empty() && (terminator_required || input.peek(Token![,])) {
92 input.parse::<Token![,]>()?;
93 }
94 Ok(SplitArm { dir, body: arm })
95 }
96}
97
98struct ChoiceArm {
102 index: Spanned<usize>,
104 body: Spanned<Syntax>,
106}
107
108impl Parse for ChoiceArm {
109 fn parse(input: ParseStream) -> Result<Self> {
110 let index_lit = input.parse::<LitInt>()?;
111 let index_span = index_lit.span();
112 let index = index_lit
113 .base10_parse::<usize>()
114 .map_err(|e| input.error(e))?;
115 let _ = input.parse::<Token![=>]>()?;
116 let terminator_required = requires_terminator(&input);
117 let arm = input.parse::<Spanned<Syntax>>()?;
118 if !input.is_empty() && (terminator_required || input.peek(Token![,])) {
119 input.parse::<Token![,]>()?;
120 }
121 Ok(ChoiceArm {
122 index: Spanned {
123 inner: index,
124 span: index_span,
125 },
126 body: arm,
127 })
128 }
129}
130
131struct Block(Spanned<Syntax>);
133
134fn requires_terminator(input: ParseStream) -> bool {
137 let terminator_not_required = input.peek(token::Brace)
142 || (input.peek(kw::call) && input.peek2(token::Brace))
143 || input.peek(kw::split)
144 || input.peek(kw::choose)
145 || input.peek(kw::offer)
146 || input.peek(Token![loop])
147 || input.peek(Lifetime);
148 !terminator_not_required
149}
150
151impl Parse for Block {
152 fn parse(input: ParseStream) -> Result<Self> {
153 let block_span = input.span();
155 let content;
156 braced!(content in input);
157 let mut nodes = Vec::new();
158 while !content.is_empty() {
159 let terminator_required = requires_terminator(&content);
160 nodes.push(content.parse::<Spanned<Syntax>>()?);
161
162 if !content.is_empty() && (terminator_required || content.peek(Token![;])) {
163 content.parse::<Token![;]>()?;
164 }
165 }
166
167 Ok(Block(Spanned {
168 inner: Syntax::Block(nodes),
169 span: block_span,
170 }))
171 }
172}
173
174impl Parse for Spanned<Syntax> {
175 fn parse(input: ParseStream) -> Result<Self> {
176 fn with_span<T: SpannedExt>(span: &mut Span, thing: T) -> T {
180 *span = span.join(thing.span()).unwrap_or(*span);
181 thing
182 }
183
184 let lookahead = input.lookahead1();
185 if lookahead.peek(kw::recv) {
186 let recv_span = input.parse::<kw::recv>()?.span();
188 Ok(Spanned {
189 inner: Syntax::Recv(input.parse::<Type>()?),
190 span: recv_span,
191 })
192 } else if lookahead.peek(kw::send) {
193 let send_span = input.parse::<kw::send>()?.span();
195 Ok(Spanned {
196 inner: Syntax::Send(input.parse::<Type>()?),
197 span: send_span,
198 })
199 } else if lookahead.peek(kw::call) {
200 let call_span = input.parse::<kw::call>()?.span();
202 let lookahead = input.lookahead1();
203
204 let callee = if lookahead.peek(token::Brace) {
205 input.parse::<Block>()?.0
206 } else if kw::peek_any(input) {
207 return Err(input.error("expected a block or a type, but found a keyword"));
208 } else {
209 let ty = input.parse::<Type>().map_err(|mut e| {
210 e.combine(lookahead.error());
211 e
212 })?;
213
214 let span = ty.span();
215
216 Spanned {
217 inner: Syntax::Type(ty),
218 span,
219 }
220 };
221
222 Ok(Spanned {
223 inner: Syntax::Call(Box::new(callee)),
224 span: call_span,
225 })
226 } else if lookahead.peek(kw::choose) {
227 let kw_span = input.parse::<kw::choose>()?.span();
229 let choose_span = kw_span.join(input.span()).unwrap_or(kw_span);
230
231 let content;
232 braced!(content in input);
233 let mut choice_arms = Vec::new();
234 while !content.is_empty() {
235 choice_arms.push(content.parse::<ChoiceArm>()?);
236 }
237
238 let mut arm_asts = Vec::new();
239 for (i, choice_arm) in choice_arms.into_iter().enumerate() {
240 if i != choice_arm.index.inner as usize {
241 return Err(Error::new(
242 choice_arm.index.span,
243 format!(
244 "expected index {} in `choose` construct, found {}",
245 i, choice_arm.index.inner
246 ),
247 ));
248 }
249
250 arm_asts.push(choice_arm.body);
251 }
252
253 Ok(Spanned {
254 inner: Syntax::Choose(arm_asts),
255 span: choose_span,
256 })
257 } else if lookahead.peek(kw::offer) {
258 let kw_span = input.parse::<kw::offer>()?.span();
260 let offer_span = kw_span.join(input.span()).unwrap_or(kw_span);
261
262 let content;
263 braced!(content in input);
264 let mut choice_arms = Vec::new();
265 while !content.is_empty() {
266 choice_arms.push(content.parse::<ChoiceArm>()?);
267 }
268
269 let mut arm_asts = Vec::new();
270 for (i, choice_arm) in choice_arms.into_iter().enumerate() {
271 if i != choice_arm.index.inner as usize {
272 return Err(Error::new(
273 choice_arm.index.span,
274 format!(
275 "expected index {} in `offer` construct, found {}",
276 i, choice_arm.index.inner
277 ),
278 ));
279 }
280
281 arm_asts.push(choice_arm.body);
282 }
283
284 Ok(Spanned {
285 inner: Syntax::Offer(arm_asts),
286 span: offer_span,
287 })
288 } else if lookahead.peek(kw::split) {
289 let kw_span = input.parse::<kw::split>()?.span();
291 let split_span = kw_span.join(input.span()).unwrap_or(kw_span);
292
293 let content;
294 braced!(content in input);
295 let mut split_arms = Vec::new();
296 while !content.is_empty() {
297 split_arms.push(content.parse::<SplitArm>()?);
298 }
299
300 if split_arms.len() != 2 || split_arms[0].dir == split_arms[1].dir {
301 return Err(input.error(
302 "split constructs must have exactly two arms, one Transmit and one inbound",
303 ));
304 }
305
306 if split_arms[0].dir == Direction::Receive {
307 split_arms.swap(0, 1);
308 }
309
310 Ok(Spanned {
311 inner: Syntax::Split {
312 tx_only: Box::new(split_arms[0].body.clone()),
313 rx_only: Box::new(split_arms[1].body.clone()),
314 },
315 span: split_span,
316 })
317 } else if lookahead.peek(Token![loop]) || lookahead.peek(Lifetime) {
318 let mut loop_span;
320 let label = if input.peek(Lifetime) {
321 loop_span = input.span();
322 let lifetime = with_span(&mut loop_span, input.parse::<Lifetime>()?);
323 let name = lifetime.ident.to_string();
324 let _ = with_span(&mut loop_span, input.parse::<Token![:]>()?);
325 let _ = with_span(&mut loop_span, input.parse::<Token![loop]>()?);
326 Some(name)
327 } else {
328 loop_span = input.parse::<Token![loop]>()?.span();
329 None
330 };
331
332 let Block(block) = input.parse::<Block>()?;
333 Ok(Spanned {
334 inner: Syntax::Loop(label, Box::new(block)),
335 span: loop_span,
336 })
337 } else if lookahead.peek(Token![break]) {
338 let mut break_span = input.parse::<Token![break]>()?.span();
340 let label = if input.peek(Lifetime) {
341 let lifetime = input.parse::<Lifetime>()?;
342 let _ = with_span(&mut break_span, &lifetime);
343 Some(lifetime.ident.to_string())
344 } else {
345 None
346 };
347
348 Ok(Spanned {
349 inner: Syntax::Break(label),
350 span: break_span,
351 })
352 } else if lookahead.peek(Token![continue]) {
353 let mut continue_span = input.parse::<Token![continue]>()?.span();
355 let label = if input.peek(Lifetime) {
356 let lifetime = input.parse::<Lifetime>()?;
357 let _ = with_span(&mut continue_span, &lifetime);
358 Some(lifetime.ident.to_string())
359 } else {
360 None
361 };
362
363 Ok(Spanned {
364 inner: Syntax::Continue(label),
365 span: continue_span,
366 })
367 } else if lookahead.peek(token::Brace) {
368 Ok(input.parse::<Block>()?.0)
370 } else {
371 let ty = match input.parse::<Type>() {
374 Ok(ty) => ty,
375 Err(e) => {
376 let mut combined = lookahead.error();
377 combined.combine(input.error("parsing as a type failed"));
378 combined.combine(e);
379 return Err(combined);
380 }
381 };
382
383 let span = ty.span();
384
385 Ok(Spanned {
386 inner: Syntax::Type(ty),
387 span,
388 })
389 }
390 }
391}