simploxide_bindgen/syntax/
binding.rs

1//! All magic happens here. A module that generates interpreters for SimpleX chat command syntax.
2//!
3//! To add support for another language it's sufficient to implement the
4//! [`SyntaxInterpreter`] trait and then use the following builder pattern:
5//!
6//! ```ignore
7//! use simploxide_bindgen::syntax::binding::BindExt;
8//!
9//! //..
10//!
11//! let interpret_method = syntax_str
12//!     .bind(YourInterpreter::new(api_type))
13//!     // Allows to define, e.g. a function method before the interpreter body
14//!     .prelude(|intrp, out| {
15//!         bufwriteln!(out, :> 4, "def interpret(self):");
16//!         intrp.offset = 8;
17//!     })
18//!     .generate()?;
19//! ```
20
21use crate::{
22    syntax::{EnumSubstitutions, MaybeBool, lex},
23    types::{self, ApiType, EnumType, Field, RecordType, enum_type::EnumVariant},
24};
25use std::fmt::Write as _;
26
27use super::SyntaxElement;
28
29#[macro_export]
30macro_rules! bufwriteln {
31    ($dst:expr, :>$offset:expr, $($args:tt)*) => {
32        write!($dst, "{0:>1$}", " ", $offset).unwrap();
33        writeln!($dst, $($args)*).unwrap();
34    };
35    ($dst:expr, $($args:tt)*) => {
36        writeln!($dst, $($args)*).unwrap();
37    };
38}
39
40/// Represents a type with a syntax that can be interpreted as a SimpleX command. The impl should
41/// return Ok(None) when the syntax string is empty or return full implementation of the following
42/// trait:
43///
44/// ```ignore
45/// trait CommandSyntax {
46///     fn interpret(&self) -> String;
47/// }
48/// ```
49///
50/// The trait definition itself must be generated by the client manually somewhere
51pub trait Interpretable {
52    fn command_syntax_impl(&self) -> Result<Option<String>, String>;
53}
54
55impl Interpretable for ApiType {
56    fn command_syntax_impl(&self) -> Result<Option<String>, String> {
57        match self {
58            ApiType::Record(record_type) => record_type.command_syntax_impl(),
59            ApiType::DiscriminatedUnion(_) => Ok(None),
60            ApiType::Enum(enum_type) => enum_type.command_syntax_impl(),
61        }
62    }
63}
64
65impl Interpretable for EnumType {
66    fn command_syntax_impl(&self) -> Result<Option<String>, String> {
67        self.syntax
68            .bind(EnumInterpreter::with_offset(self, 8))
69            .prelude(|_, code_buffer| {
70                bufwriteln!(code_buffer, "impl CommandSyntax for {} {{", self.name);
71                bufwriteln!(code_buffer, :>4, "fn interpret(&self) -> String {{",);
72                bufwriteln!(code_buffer, :>8, "let mut buf = String::new();");
73                Ok(())
74            })
75            .postlude(|_, code_buffer| {
76                bufwriteln!(code_buffer, :>8, "buf",);
77                bufwriteln!(code_buffer, :>4, "}}",);
78                bufwriteln!(code_buffer, "}}",);
79                Ok(())
80            })
81            .generate()
82            .map_err(|e| format!("{e} in syntax {} of the enum type\n{}", self.syntax, self))
83    }
84}
85
86impl Interpretable for RecordType {
87    fn command_syntax_impl(&self) -> Result<Option<String>, String> {
88        self.syntax
89            .bind(RecordInterpreter::with_offset(self, 8))
90            .prelude(|_, out| {
91                bufwriteln!(out, "impl CommandSyntax for {} {{", self.name);
92                bufwriteln!(out, :>4, "fn interpret(&self) -> String {{",);
93
94                if self.syntax.contains("json(") {
95                    bufwriteln!(out, :>8, "let mut buf = String::with_capacity(1024);");
96                } else if self.fields.len() > 2 || self.syntax.contains("[0]>") {
97                    bufwriteln!(out, :>8, "let mut buf = String::with_capacity(256);");
98                } else if self.fields.is_empty() {
99                    bufwriteln!(out, :>8, "let mut buf = String::new();");
100                } else {
101                    bufwriteln!(out, :>8, "let mut buf = String::with_capacity(64);");
102                }
103
104                Ok(())
105            })
106            .postlude(|_, out| {
107                bufwriteln!(out, :>8, "buf");
108                bufwriteln!(out, :>4, "}}");
109                bufwriteln!(out, "}}");
110                Ok(())
111            })
112            .generate()
113            .map_err(|e| format!("{e} in syntax {} of the record type\n{}", self.syntax, self))
114    }
115}
116
117pub type SyntaxInterpreterResult<'a, T, E> = Result<T, SyntaxInterpreterError<'a, E>>;
118
119/// Implement `interpret_` methods and use the provided [`Self::interpret_syntax`] to generate the
120/// whole interpreter body from the syntax.
121///
122/// It's not recommended to use [`Self::interpret_syntax`] directly though, use [`Generator`] that allows to
123/// generate some code around the interpreter body.
124///
125/// By default all methods return [`SyntaxInterpreterError::Unexpected`] error.
126///
127/// The SyntaxElement<'_> parameter is included into each method only to make errors more
128/// informative.
129pub trait SyntaxInterpreter {
130    /// A data that is passed between optional and non-optional contexts. Effectively acts as a
131    /// stack frame that can be used to decide how to render items in [`SyntaxElement::Optional`]
132    /// after processing the optional scope. For example, in Rust this can help to decide which
133    /// syntax to use for the if statement.
134    ///
135    /// Set it to `()` if you don't need it.
136    type ContextData;
137
138    /// A type used in SyntaxInterpreterError::Custom variant.
139    type Error;
140
141    fn interpret_literal<'a>(
142        &mut self,
143        el: SyntaxElement<'a>,
144        _lit: &'a str,
145        _ctx: Option<&mut Self::ContextData>,
146        _out: &mut String,
147    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
148        Err(SyntaxInterpreterError::Unexpected(el))
149    }
150
151    fn interpret_bool<'a>(
152        &mut self,
153        el: SyntaxElement<'a>,
154        _maybe_bool: MaybeBool,
155        _ctx: Option<&mut Self::ContextData>,
156        _out: &mut String,
157    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
158        Err(SyntaxInterpreterError::Unexpected(el))
159    }
160
161    fn interpret_enum_substitutions<'a>(
162        &mut self,
163        el: SyntaxElement<'a>,
164        _enum_subs: EnumSubstitutions<'a>,
165        _ctx: Option<&mut Self::ContextData>,
166        _out: &mut String,
167    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
168        Err(SyntaxInterpreterError::Unexpected(el))
169    }
170
171    fn interpret_trivial_substitution<'a>(
172        &mut self,
173        el: SyntaxElement<'a>,
174        _member_to_sub: &'a str,
175        _ctx: Option<&mut Self::ContextData>,
176        _out: &mut String,
177    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
178        Err(SyntaxInterpreterError::Unexpected(el))
179    }
180
181    fn interpret_delegate_substitution<'a>(
182        &mut self,
183        el: SyntaxElement<'a>,
184        _member_to_sub: &'a str,
185        _ctx: Option<&mut Self::ContextData>,
186        _out: &mut String,
187    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
188        Err(SyntaxInterpreterError::Unexpected(el))
189    }
190
191    fn interpret_json_substitution<'a>(
192        &mut self,
193        el: SyntaxElement<'a>,
194        _member_to_sub: &'a str,
195        _ctx: Option<&mut Self::ContextData>,
196        _out: &mut String,
197    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
198        Err(SyntaxInterpreterError::Unexpected(el))
199    }
200
201    fn interpret_vec_substitution<'a>(
202        &mut self,
203        el: SyntaxElement<'a>,
204        _member_to_sub: &'a str,
205        _delim: &'a str,
206        _ctx: Option<&mut Self::ContextData>,
207        _out: &mut String,
208    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
209        Err(SyntaxInterpreterError::Unexpected(el))
210    }
211
212    /// Invoked before diving into the optional context. Should return an instance of
213    /// [`Self::ContextData`] that can be mutated by the interpret calls. Then
214    /// [`Self::ContextData`] will be consumed consumed by the matching
215    /// [`Self::interpret_optional_context_exit`].
216    ///
217    /// This [`Self::ContextData`] may be used to decide how to adjust the surrounding code
218    /// depending on the contents of the opitonal context.
219    ///
220    /// If you don't need [`Self::ContextData`] set it to `()`.
221    fn interpret_optional_context_enter<'a>(
222        &mut self,
223        el: SyntaxElement<'a>,
224        _out: &mut String,
225    ) -> SyntaxInterpreterResult<'a, Self::ContextData, Self::Error> {
226        Err(SyntaxInterpreterError::Unexpected(el))
227    }
228
229    /// Invoked right after the optional context was fully processed. Consumes [`Self::ContextData`] tha
230    /// created by the matching `interprert_optional_context_enter`.
231    fn interpret_optional_context_exit<'a>(
232        &mut self,
233        _el: SyntaxElement<'a>,
234        _ctx: Self::ContextData,
235        _out: &mut String,
236    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
237        Ok(())
238    }
239
240    /// Generates the full body from `syntax`
241    fn interpret_syntax<'a>(
242        &mut self,
243        syntax: &'a str,
244        mut ctx: Option<&mut Self::ContextData>,
245        out: &mut String,
246    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
247        for tok in lex(syntax) {
248            let el = tok.map_err(SyntaxInterpreterError::Lexer)?;
249
250            match el {
251                SyntaxElement::Literal(lit) => {
252                    self.interpret_literal(el, lit, ctx.as_deref_mut(), out)?
253                }
254                SyntaxElement::EnumSubstitutions(enum_subs) => {
255                    self.interpret_enum_substitutions(el, enum_subs, ctx.as_deref_mut(), out)?
256                }
257                SyntaxElement::MaybeBool(maybe_bool) => {
258                    self.interpret_bool(el, maybe_bool, ctx.as_deref_mut(), out)?
259                }
260                SyntaxElement::TrivialMemberSubstitution { member_name } => {
261                    self.interpret_trivial_substitution(el, member_name, ctx.as_deref_mut(), out)?
262                }
263                SyntaxElement::DelegateMemberSubstitution { member_name } => {
264                    self.interpret_delegate_substitution(el, member_name, ctx.as_deref_mut(), out)?
265                }
266                SyntaxElement::JsonMemberSubstitution { member_name } => {
267                    self.interpret_json_substitution(el, member_name, ctx.as_deref_mut(), out)?
268                }
269                SyntaxElement::VecMemberSubstitution { member_name, delim } => self
270                    .interpret_vec_substitution(el, member_name, delim, ctx.as_deref_mut(), out)?,
271                SyntaxElement::Optional { unparsed } => {
272                    let mut new_ctx = self.interpret_optional_context_enter(el, out)?;
273                    self.interpret_syntax(unparsed, Some(&mut new_ctx), out)?;
274                    self.interpret_optional_context_exit(el, new_ctx, out)?;
275                }
276            }
277        }
278        Ok(())
279    }
280}
281
282pub enum SyntaxInterpreterError<'a, E: 'a> {
283    Unexpected(SyntaxElement<'a>),
284    Lexer(String),
285    Custom(E),
286}
287
288impl<'a, E: 'a + std::fmt::Display> std::fmt::Display for SyntaxInterpreterError<'a, E> {
289    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290        match self {
291            Self::Unexpected(el) => writeln!(f, "Unexpected syntax element {el:?}"),
292            Self::Lexer(err) => writeln!(f, "Lexer error: {err}"),
293            Self::Custom(err) => writeln!(f, "{err}"),
294        }
295    }
296}
297
298/// It's just a simple closure that provides (interpreter, out_buffer) in its arguments and allows
299/// borrowing the outside context.
300pub type DeferredGeneration<'s, SI> = Box<
301    dyn 's
302        + FnOnce(
303            &mut SI,
304            &mut String,
305        ) -> SyntaxInterpreterResult<'s, (), <SI as SyntaxInterpreter>::Error>,
306>;
307
308/// A helper type that consumes the interpreter and generates the whole code block with it. The
309/// block itself is generated with `prelude` and `postlude` callbacks. E.g. for Python this snippet
310/// can be used to generate the interpret method:
311///
312/// ```ignore
313/// record_type
314///     .syntax
315///     .bind(PythonRecordInterpreter::new(&record_type))
316///     .prelude(|intrp, out| {
317///         bufwriteln!(out, :>4, "def interpret(self):");
318///         intrp.offset = 8;
319///     })
320///     // There is no need to use the .postlude(|intrp, out|) callback because
321///     // in Python functions and methods don't have closing brackets or keywords
322///     .generate()?;
323/// ```
324///
325/// To construct the generator witt a bind method import [`BindExt`] trait.
326pub struct Generator<'s, SI: SyntaxInterpreter> {
327    syntax: &'s str,
328    interpreter: SI,
329    make_prelude: Option<DeferredGeneration<'s, SI>>,
330    make_postlude: Option<DeferredGeneration<'s, SI>>,
331}
332
333impl<'s, SI: SyntaxInterpreter> Generator<'s, SI> {
334    pub fn new(syntax: &'s str, interpreter: SI) -> Self {
335        Self {
336            syntax,
337            interpreter,
338            make_prelude: None,
339            make_postlude: None,
340        }
341    }
342
343    pub fn prelude<F>(mut self, f: F) -> Self
344    where
345        F: 's + FnOnce(&mut SI, &mut String) -> SyntaxInterpreterResult<'s, (), SI::Error>,
346    {
347        self.make_prelude = Some(Box::new(f));
348        self
349    }
350
351    pub fn postlude<F>(mut self, f: F) -> Self
352    where
353        F: 's + FnOnce(&mut SI, &mut String) -> SyntaxInterpreterResult<'s, (), SI::Error>,
354    {
355        self.make_postlude = Some(Box::new(f));
356        self
357    }
358
359    pub fn generate(self) -> SyntaxInterpreterResult<'s, Option<String>, SI::Error> {
360        if self.syntax.is_empty() {
361            return Ok(None);
362        }
363
364        let mut code_buffer = String::with_capacity(4096);
365
366        let Self {
367            syntax,
368            mut interpreter,
369            make_prelude,
370            make_postlude,
371        } = self;
372
373        if let Some(f) = make_prelude {
374            f(&mut interpreter, &mut code_buffer)?;
375        }
376
377        interpreter.interpret_syntax(syntax, None, &mut code_buffer)?;
378
379        if let Some(f) = make_postlude {
380            f(&mut interpreter, &mut code_buffer)?;
381        }
382
383        Ok(Some(code_buffer))
384    }
385}
386
387/// This trait exists to provide syntactic sugar to create the generator builder from str:
388///
389/// ```ignore
390/// "/_command <str(userId)>"
391///     .bind(SomeInterpreter)
392///     .prelude(..)
393///     .postlude(..)
394///     .generate();
395/// ```
396pub trait BindExt<SI: SyntaxInterpreter> {
397    fn bind(&self, interpreter: SI) -> Generator<'_, SI>;
398}
399
400impl<SI: SyntaxInterpreter> BindExt<SI> for str {
401    fn bind(&self, interpreter: SI) -> Generator<'_, SI> {
402        Generator::new(self, interpreter)
403    }
404}
405
406type VariantName<'a> = &'a str;
407type VariantLiteral<'a> = &'a str;
408
409struct EnumInterpreter<'a> {
410    typ: &'a EnumType,
411    offset: usize,
412}
413
414impl<'a> EnumInterpreter<'a> {
415    fn with_offset(typ: &'a EnumType, offset: usize) -> Self {
416        Self { typ, offset }
417    }
418
419    fn interpret_subs(
420        &self,
421        subs: &EnumSubstitutions,
422        from_field: Option<&Field>,
423        code_buffer: &mut String,
424    ) -> Result<(), EnumInterpreterErr> {
425        let (accessor, enum_ref) = match from_field {
426            Some(field) => (format!(".{}", field.rust_name), self.typ.name.as_str()),
427            None => (String::new(), "Self"),
428        };
429
430        let offset = self.offset;
431
432        bufwriteln!(code_buffer, :>offset, "match self{accessor} {{");
433        for (var_name, literal) in self.variant_substitutions(subs)? {
434            bufwriteln!(code_buffer, :>offset + 4, "{enum_ref}::{var_name} => {{");
435            interpret_literal(literal, offset + 8, code_buffer);
436            bufwriteln!(code_buffer, :>offset + 4, "}}");
437        }
438        bufwriteln!(code_buffer, :>offset, "}}");
439        Ok(())
440    }
441
442    fn variant_substitutions<'s>(
443        &self,
444        enum_subs: &'s EnumSubstitutions<'s>,
445    ) -> Result<impl Iterator<Item = (VariantName<'a>, VariantLiteral<'s>)>, EnumInterpreterErr>
446    {
447        let literals_count = enum_subs.iter().count();
448
449        if self.typ.variants.len() != enum_subs.iter().count() {
450            return Err(EnumInterpreterErr {
451                expected: self.typ.variants.len(),
452                got: literals_count,
453            });
454        }
455
456        Ok(self
457            .typ
458            .variants
459            .iter()
460            .map(|var| var.rust_name.as_str())
461            .zip(enum_subs.iter()))
462    }
463}
464
465impl<'this> SyntaxInterpreter for EnumInterpreter<'this> {
466    type Error = EnumInterpreterErr;
467    type ContextData = ();
468
469    fn interpret_literal<'a>(
470        &mut self,
471        _el: SyntaxElement<'a>,
472        lit: &'a str,
473        _ctx: Option<&mut Self::ContextData>,
474        out: &mut String,
475    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
476        interpret_literal(lit, self.offset, out);
477        Ok(())
478    }
479
480    fn interpret_enum_substitutions<'a>(
481        &mut self,
482        _el: SyntaxElement<'a>,
483        enum_subs: EnumSubstitutions<'a>,
484        _ctx: Option<&mut Self::ContextData>,
485        out: &mut String,
486    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
487        self.interpret_subs(&enum_subs, None, out)
488            .map_err(SyntaxInterpreterError::Custom)?;
489
490        Ok(())
491    }
492}
493
494pub struct EnumInterpreterErr {
495    expected: usize,
496    got: usize,
497}
498
499impl std::fmt::Display for EnumInterpreterErr {
500    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
501        writeln!(
502            f,
503            "The enum has only {} variants, while the syntax defines {}",
504            self.expected, self.got
505        )
506    }
507}
508
509struct RecordInterpreter<'a> {
510    typ: &'a RecordType,
511    curr_field_ix: usize,
512    offset: usize,
513}
514
515impl<'a> RecordInterpreter<'a> {
516    fn with_offset(typ: &'a RecordType, offset: usize) -> Self {
517        Self {
518            typ,
519            curr_field_ix: 0,
520            offset,
521        }
522    }
523
524    fn current_field<'el>(
525        &self,
526        el: SyntaxElement<'el>,
527    ) -> SyntaxInterpreterResult<'el, &'a Field, String> {
528        self
529            .typ
530            .fields
531            .get(self.curr_field_ix)
532            .ok_or_else(|| {
533                SyntaxInterpreterError::Custom(format!("Expected a field while processing an element {el:?} but found None(current_field_ix={})", self.curr_field_ix))
534            })
535    }
536
537    fn field_by_api_name<'el>(
538        &mut self,
539        api_name: &str,
540        el: SyntaxElement<'el>,
541    ) -> SyntaxInterpreterResult<'el, &'a Field, String> {
542        loop {
543            let field = self.typ.fields.get(self.curr_field_ix).ok_or_else(|| {
544                SyntaxInterpreterError::Custom(format!("Failed to find a struct field with the name: {api_name:?} while trying to match element {el:?}"))
545            })?;
546
547            if field.api_name == api_name {
548                return Ok(field);
549            }
550
551            self.curr_field_ix += 1;
552        }
553    }
554}
555
556impl<'this> SyntaxInterpreter for RecordInterpreter<'this> {
557    type Error = String;
558    type ContextData = RecordContextData<'this>;
559
560    fn interpret_literal<'a>(
561        &mut self,
562        _el: SyntaxElement<'a>,
563        lit: &'a str,
564        ctx: Option<&mut Self::ContextData>,
565        out: &mut String,
566    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
567        match ctx {
568            Some(frame) => interpret_literal(lit, self.offset, &mut frame.buffer),
569            None => interpret_literal(lit, self.offset, out),
570        }
571
572        Ok(())
573    }
574
575    fn interpret_bool<'a>(
576        &mut self,
577        el: SyntaxElement<'a>,
578        maybe_bool: MaybeBool,
579        ctx: Option<&mut Self::ContextData>,
580        out: &mut String,
581    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
582        match maybe_bool {
583            MaybeBool::On | MaybeBool::Off => {
584                if let Some(frame) = ctx {
585                    let maybe_bool_field = self.current_field(el)?;
586
587                    if !maybe_bool_field.is_bool() {
588                        return Err(SyntaxInterpreterError::Custom(format!(
589                            "Expected a regular bool field but got {maybe_bool:?} while processing an element {el:?} in the optional span"
590                        )));
591                    }
592                    if maybe_bool == MaybeBool::On {
593                        interpret_literal("on", self.offset, &mut frame.buffer);
594                        frame.cond_kind = CondKind::Bool(maybe_bool_field);
595                    } else {
596                        interpret_literal("off", self.offset, &mut frame.buffer);
597                        frame.cond_kind = CondKind::NotBool(maybe_bool_field);
598                    }
599                } else {
600                    return Err(SyntaxInterpreterError::Custom(
601                        "Unexpexted non-optional '{val:?}' literal that doesn't provide a choice. Expected (on|off)"
602                            .to_owned(),
603                    ));
604                }
605            }
606            MaybeBool::Either => {
607                let bool_field = self.current_field(el)?;
608
609                let (self_str, deref, dest) = if let Some(frame) = ctx {
610                    if !bool_field.is_optional() {
611                        return Err(SyntaxInterpreterError::Custom(format!(
612                            "Expected an optional bool field but got {bool_field:?} while processing an element {el:?}"
613                        )));
614                    }
615
616                    frame.cond_kind = CondKind::Opt(bool_field);
617                    ("", "*", &mut frame.buffer)
618                } else {
619                    if !bool_field.is_bool() {
620                        return Err(SyntaxInterpreterError::Custom(format!(
621                            "The current field must be a bool, but instead it's a {bool_field:?} for element {el:?}",
622                        )));
623                    }
624
625                    ("self.", "", out)
626                };
627
628                bufwriteln!(dest, :> self.offset, "if {deref}{self_str}{} {{", bool_field.rust_name);
629                interpret_literal("on", self.offset + 4, dest);
630                bufwriteln!(dest, :> self.offset, "}} else {{");
631                interpret_literal("off", self.offset + 4, dest);
632                bufwriteln!(dest, :> self.offset, "}}");
633            }
634        }
635
636        self.curr_field_ix += 1;
637        Ok(())
638    }
639
640    fn interpret_enum_substitutions<'a>(
641        &mut self,
642        el: SyntaxElement<'a>,
643        enum_subs: EnumSubstitutions<'a>,
644        ctx: Option<&mut Self::ContextData>,
645        out: &mut String,
646    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
647        if ctx.is_some() {
648            // Add on demand
649            return Err(SyntaxInterpreterError::Custom(format!(
650                "Enum substitutions are unsupported in optional contexts, but got {el:?}",
651            )));
652        }
653
654        let field = self.current_field(el)?;
655
656        if !field.is_compound() {
657            return Err(SyntaxInterpreterError::Custom(format!(
658                "Expected a enum field but got a {:?} field while processing {el:?}",
659                field.typ,
660            )));
661        }
662
663        let ad_hoc_enum = EnumType::new(
664            field.typ.clone(),
665            enum_subs.iter().map(EnumVariant::from_api_name).collect(),
666        );
667
668        let interpreter = EnumInterpreter::with_offset(&ad_hoc_enum, self.offset);
669        interpreter
670            .interpret_subs(&enum_subs, Some(field), out)
671            .map_err(|e| SyntaxInterpreterError::Custom(e.to_string()))?;
672
673        self.curr_field_ix += 1;
674        Ok(())
675    }
676
677    fn interpret_trivial_substitution<'a>(
678        &mut self,
679        el: SyntaxElement<'a>,
680        member_to_sub: &'a str,
681        ctx: Option<&mut Self::ContextData>,
682        out: &mut String,
683    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
684        let field = self.field_by_api_name(member_to_sub, el)?;
685
686        let (self_str, unwrap, dest) = match ctx {
687            Some(frame) => {
688                frame.cond_kind = CondKind::Opt(field);
689                ("", "", &mut frame.buffer)
690            }
691            None => ("self.", maybe_unwrap(field), out),
692        };
693
694        bufwriteln!(dest, :> self.offset, "buf.push_str(&{self_str}{}{unwrap}.to_string());", field.rust_name);
695
696        self.curr_field_ix += 1;
697        Ok(())
698    }
699
700    fn interpret_delegate_substitution<'a>(
701        &mut self,
702        el: SyntaxElement<'a>,
703        member_to_sub: &'a str,
704        ctx: Option<&mut Self::ContextData>,
705        out: &mut String,
706    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
707        let field = self.field_by_api_name(member_to_sub, el)?;
708
709        let (self_str, dest) = match ctx {
710            Some(frame) => {
711                frame.cond_kind = CondKind::Opt(field);
712                ("", &mut frame.buffer)
713            }
714            None => ("self.", out),
715        };
716
717        bufwriteln!(dest, :> self.offset, "buf.push_str(&{self_str}{}.interpret());", field.rust_name);
718
719        self.curr_field_ix += 1;
720        Ok(())
721    }
722
723    fn interpret_json_substitution<'a>(
724        &mut self,
725        el: SyntaxElement<'a>,
726        member_to_sub: &'a str,
727        ctx: Option<&mut Self::ContextData>,
728        out: &mut String,
729    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
730        let field = self.field_by_api_name(member_to_sub, el)?;
731
732        let (self_str, dest) = match ctx {
733            Some(frame) => {
734                frame.cond_kind = CondKind::Opt(field);
735                ("", &mut frame.buffer)
736            }
737            None => ("self.", out),
738        };
739
740        bufwriteln!(
741            dest,
742            :> self.offset, "buf.push_str(&serde_json::to_string(&{self_str}{}).unwrap());",
743            field.rust_name,
744        );
745
746        self.curr_field_ix += 1;
747        Ok(())
748    }
749
750    fn interpret_vec_substitution<'a>(
751        &mut self,
752        el: SyntaxElement<'a>,
753        member_to_sub: &'a str,
754        delim: &'a str,
755        ctx: Option<&mut Self::ContextData>,
756        out: &mut String,
757    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
758        let field = self.field_by_api_name(member_to_sub, el)?;
759
760        let (self_str, unwrap, dest) = match ctx {
761            Some(frame) => {
762                frame.cond_kind = CondKind::Opt(field);
763                ("", "", &mut frame.buffer)
764            }
765            None => ("self.", maybe_unwrap(field), out),
766        };
767
768        bufwriteln!(dest, :> self.offset, "let mut iter = {self_str}{}{unwrap}.iter();", field.rust_name);
769        bufwriteln!(dest, :> self.offset, "if let Some(el) = iter.next() {{");
770        bufwriteln!(dest, :> self.offset + 4, "buf.push_str(&el.to_string());");
771        bufwriteln!(dest, :> self.offset, "}}");
772        bufwriteln!(dest, :> self.offset, "for el in iter {{");
773        interpret_literal(delim, self.offset + 4, dest);
774        bufwriteln!(dest, :> self.offset + 4, "buf.push_str(&el.to_string());");
775        bufwriteln!(dest, :> self.offset, "}}");
776
777        self.curr_field_ix += 1;
778        Ok(())
779    }
780
781    fn interpret_optional_context_enter<'a>(
782        &mut self,
783        _el: SyntaxElement<'a>,
784        _out: &mut String,
785    ) -> SyntaxInterpreterResult<'a, Self::ContextData, Self::Error> {
786        self.offset += 4;
787        Ok(RecordContextData {
788            buffer: String::with_capacity(256),
789            cond_kind: CondKind::None,
790        })
791    }
792
793    fn interpret_optional_context_exit<'a>(
794        &mut self,
795        el: SyntaxElement<'a>,
796        ctx: Self::ContextData,
797        out: &mut String,
798    ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
799        self.offset -= 4;
800
801        match ctx.cond_kind {
802            CondKind::Bool(field) => {
803                bufwriteln!(out, :> self.offset, "if self.{} {{", field.rust_name);
804            }
805            CondKind::NotBool(field) => {
806                bufwriteln!(out, :> self.offset, "if !self.{} {{", field.rust_name);
807            }
808            CondKind::Opt(field) => {
809                bufwriteln!(out, :> self.offset, "if let Some({0}) = &self.{0} {{", field.rust_name);
810            }
811            CondKind::None => {
812                return Err(SyntaxInterpreterError::Custom(format!(
813                    "Failed to deduce a field type in optional context while processing {el:?}"
814                )));
815            }
816        }
817
818        out.push_str(&ctx.buffer);
819
820        bufwriteln!(out, :> self.offset, "}}");
821        Ok(())
822    }
823}
824
825pub struct RecordContextData<'a> {
826    buffer: String,
827    cond_kind: CondKind<'a>,
828}
829
830enum CondKind<'a> {
831    Bool(&'a Field),
832    NotBool(&'a Field),
833    Opt(&'a Field),
834    None,
835}
836
837fn interpret_literal(literal: &str, offset: usize, code_buffer: &mut String) {
838    if literal.len() == 1 {
839        bufwriteln!(code_buffer, :>offset, "buf.push('{literal}');");
840    } else {
841        bufwriteln!(code_buffer, :>offset, "buf.push_str(\"{literal}\");");
842    }
843}
844
845fn maybe_unwrap(field: &Field) -> &'static str {
846    if let Some(inner) = field.inner_type() {
847        if field.is_optional() && types::is_string_type(inner) {
848            ".as_deref().unwrap_or_default()"
849        } else if field.is_vec() {
850            ""
851        } else {
852            ".unwrap_or_default()"
853        }
854    } else {
855        ""
856    }
857}
858
859#[cfg(test)]
860mod tests {
861    use super::*;
862    use expect_test::expect;
863
864    #[test]
865    fn enum_interpreter() {
866        let mut test_enum = EnumType::new(
867            "Greeting".to_owned(),
868            vec!["\"hi\"".parse().unwrap(), "\"bye\"".parse().unwrap()],
869        );
870
871        test_enum.syntax = "Hello,|Goodbye,| World!".to_owned();
872
873        let interpreter_impl = test_enum.command_syntax_impl().unwrap().unwrap();
874
875        expect![[r#"
876            impl CommandSyntax for Greeting {
877                fn interpret(&self) -> String {
878                    let mut buf = String::new();
879                    match self {
880                        Self::Hi => {
881                            buf.push_str("Hello,");
882                        }
883                        Self::Bye => {
884                            buf.push_str("Goodbye,");
885                        }
886                    }
887                    buf.push(' ');
888                    buf.push_str("World!");
889                    buf
890                }
891            }
892        "#]]
893        .assert_eq(&interpreter_impl);
894    }
895
896    trait CommandSyntax {
897        fn interpret(&self) -> String;
898    }
899
900    enum Greeting {
901        Hi,
902        Bye,
903    }
904
905    impl CommandSyntax for Greeting {
906        fn interpret(&self) -> String {
907            let mut buf = String::with_capacity(64);
908            match self {
909                Self::Hi => {
910                    buf.push_str("Hello,");
911                }
912                Self::Bye => {
913                    buf.push_str("Goodbye,");
914                }
915            }
916            buf.push(' ');
917            buf.push_str("World!");
918            buf
919        }
920    }
921
922    #[test]
923    fn real_greeting() {
924        assert_eq!(Greeting::Hi.interpret(), "Hello, World!");
925        assert_eq!(Greeting::Bye.interpret(), "Goodbye, World!");
926    }
927}