1use 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
40pub 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, "const COMMAND_BUF_SIZE: usize = 16;",);
72 bufwriteln!(code_buffer,);
73 bufwriteln!(code_buffer, :>4, "fn append_command_syntax(&self, buf: &mut String) {{",);
74 Ok(())
75 })
76 .postlude(|_, code_buffer| {
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 if self.syntax.contains("json(") {
93 bufwriteln!(out, :>4, "const COMMAND_BUF_SIZE: usize = 1024;");
94 } else if self.fields.len() > 2 || self.syntax.contains("[0]>") {
95 bufwriteln!(out, :>4, "const COMMAND_BUF_SIZE: usize = 256;");
96 } else if self.fields.is_empty() {
97 bufwriteln!(out, :>4, "const COMMAND_BUF_SIZE: usize = 0;");
98 } else {
99 bufwriteln!(out, :>4, "const COMMAND_BUF_SIZE: usize = 64;");
100 }
101 bufwriteln!(out,);
102 bufwriteln!(out, :>4, "fn append_command_syntax(&self, buf: &mut String) {{",);
103
104 Ok(())
105 })
106 .postlude(|_, out| {
107 bufwriteln!(out, :>4, "}}");
108 bufwriteln!(out, "}}");
109 Ok(())
110 })
111 .generate()
112 .map_err(|e| format!("{e} in syntax {} of the record type\n{}", self.syntax, self))
113 }
114}
115
116pub type SyntaxInterpreterResult<'a, T, E> = Result<T, SyntaxInterpreterError<'a, E>>;
117
118pub trait SyntaxInterpreter {
129 type ContextData;
136
137 type Error;
139
140 fn interpret_literal<'a>(
141 &mut self,
142 el: SyntaxElement<'a>,
143 _lit: &'a str,
144 _ctx: Option<&mut Self::ContextData>,
145 _out: &mut String,
146 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
147 Err(SyntaxInterpreterError::Unexpected(el))
148 }
149
150 fn interpret_bool<'a>(
151 &mut self,
152 el: SyntaxElement<'a>,
153 _maybe_bool: MaybeBool,
154 _ctx: Option<&mut Self::ContextData>,
155 _out: &mut String,
156 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
157 Err(SyntaxInterpreterError::Unexpected(el))
158 }
159
160 fn interpret_enum_substitutions<'a>(
161 &mut self,
162 el: SyntaxElement<'a>,
163 _enum_subs: EnumSubstitutions<'a>,
164 _ctx: Option<&mut Self::ContextData>,
165 _out: &mut String,
166 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
167 Err(SyntaxInterpreterError::Unexpected(el))
168 }
169
170 fn interpret_trivial_substitution<'a>(
171 &mut self,
172 el: SyntaxElement<'a>,
173 _member_to_sub: &'a str,
174 _ctx: Option<&mut Self::ContextData>,
175 _out: &mut String,
176 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
177 Err(SyntaxInterpreterError::Unexpected(el))
178 }
179
180 fn interpret_delegate_substitution<'a>(
181 &mut self,
182 el: SyntaxElement<'a>,
183 _member_to_sub: &'a str,
184 _ctx: Option<&mut Self::ContextData>,
185 _out: &mut String,
186 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
187 Err(SyntaxInterpreterError::Unexpected(el))
188 }
189
190 fn interpret_json_substitution<'a>(
191 &mut self,
192 el: SyntaxElement<'a>,
193 _member_to_sub: &'a str,
194 _ctx: Option<&mut Self::ContextData>,
195 _out: &mut String,
196 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
197 Err(SyntaxInterpreterError::Unexpected(el))
198 }
199
200 fn interpret_vec_substitution<'a>(
201 &mut self,
202 el: SyntaxElement<'a>,
203 _member_to_sub: &'a str,
204 _delim: &'a str,
205 _ctx: Option<&mut Self::ContextData>,
206 _out: &mut String,
207 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
208 Err(SyntaxInterpreterError::Unexpected(el))
209 }
210
211 fn interpret_optional_context_enter<'a>(
221 &mut self,
222 el: SyntaxElement<'a>,
223 _out: &mut String,
224 ) -> SyntaxInterpreterResult<'a, Self::ContextData, Self::Error> {
225 Err(SyntaxInterpreterError::Unexpected(el))
226 }
227
228 fn interpret_optional_context_exit<'a>(
231 &mut self,
232 _el: SyntaxElement<'a>,
233 _ctx: Self::ContextData,
234 _out: &mut String,
235 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
236 Ok(())
237 }
238
239 fn interpret_syntax<'a>(
241 &mut self,
242 syntax: &'a str,
243 mut ctx: Option<&mut Self::ContextData>,
244 out: &mut String,
245 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
246 for tok in lex(syntax) {
247 let el = tok.map_err(SyntaxInterpreterError::Lexer)?;
248
249 match el {
250 SyntaxElement::Literal(lit) => {
251 self.interpret_literal(el, lit, ctx.as_deref_mut(), out)?
252 }
253 SyntaxElement::EnumSubstitutions(enum_subs) => {
254 self.interpret_enum_substitutions(el, enum_subs, ctx.as_deref_mut(), out)?
255 }
256 SyntaxElement::MaybeBool(maybe_bool) => {
257 self.interpret_bool(el, maybe_bool, ctx.as_deref_mut(), out)?
258 }
259 SyntaxElement::TrivialMemberSubstitution { member_name } => {
260 self.interpret_trivial_substitution(el, member_name, ctx.as_deref_mut(), out)?
261 }
262 SyntaxElement::DelegateMemberSubstitution { member_name } => {
263 self.interpret_delegate_substitution(el, member_name, ctx.as_deref_mut(), out)?
264 }
265 SyntaxElement::JsonMemberSubstitution { member_name } => {
266 self.interpret_json_substitution(el, member_name, ctx.as_deref_mut(), out)?
267 }
268 SyntaxElement::VecMemberSubstitution { member_name, delim } => self
269 .interpret_vec_substitution(el, member_name, delim, ctx.as_deref_mut(), out)?,
270 SyntaxElement::Optional { unparsed } => {
271 let mut new_ctx = self.interpret_optional_context_enter(el, out)?;
272 self.interpret_syntax(unparsed, Some(&mut new_ctx), out)?;
273 self.interpret_optional_context_exit(el, new_ctx, out)?;
274 }
275 }
276 }
277 Ok(())
278 }
279}
280
281pub enum SyntaxInterpreterError<'a, E: 'a> {
282 Unexpected(SyntaxElement<'a>),
283 Lexer(String),
284 Custom(E),
285}
286
287impl<'a, E: 'a + std::fmt::Display> std::fmt::Display for SyntaxInterpreterError<'a, E> {
288 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
289 match self {
290 Self::Unexpected(el) => writeln!(f, "Unexpected syntax element {el:?}"),
291 Self::Lexer(err) => writeln!(f, "Lexer error: {err}"),
292 Self::Custom(err) => writeln!(f, "{err}"),
293 }
294 }
295}
296
297pub type DeferredGeneration<'s, SI> = Box<
300 dyn 's
301 + FnOnce(
302 &mut SI,
303 &mut String,
304 ) -> SyntaxInterpreterResult<'s, (), <SI as SyntaxInterpreter>::Error>,
305>;
306
307pub struct Generator<'s, SI: SyntaxInterpreter> {
326 syntax: &'s str,
327 interpreter: SI,
328 make_prelude: Option<DeferredGeneration<'s, SI>>,
329 make_postlude: Option<DeferredGeneration<'s, SI>>,
330}
331
332impl<'s, SI: SyntaxInterpreter> Generator<'s, SI> {
333 pub fn new(syntax: &'s str, interpreter: SI) -> Self {
334 Self {
335 syntax,
336 interpreter,
337 make_prelude: None,
338 make_postlude: None,
339 }
340 }
341
342 pub fn prelude<F>(mut self, f: F) -> Self
343 where
344 F: 's + FnOnce(&mut SI, &mut String) -> SyntaxInterpreterResult<'s, (), SI::Error>,
345 {
346 self.make_prelude = Some(Box::new(f));
347 self
348 }
349
350 pub fn postlude<F>(mut self, f: F) -> Self
351 where
352 F: 's + FnOnce(&mut SI, &mut String) -> SyntaxInterpreterResult<'s, (), SI::Error>,
353 {
354 self.make_postlude = Some(Box::new(f));
355 self
356 }
357
358 pub fn generate(self) -> SyntaxInterpreterResult<'s, Option<String>, SI::Error> {
359 if self.syntax.is_empty() {
360 return Ok(None);
361 }
362
363 let mut code_buffer = String::with_capacity(4096);
364
365 let Self {
366 syntax,
367 mut interpreter,
368 make_prelude,
369 make_postlude,
370 } = self;
371
372 if let Some(f) = make_prelude {
373 f(&mut interpreter, &mut code_buffer)?;
374 }
375
376 interpreter.interpret_syntax(syntax, None, &mut code_buffer)?;
377
378 if let Some(f) = make_postlude {
379 f(&mut interpreter, &mut code_buffer)?;
380 }
381
382 Ok(Some(code_buffer))
383 }
384}
385
386pub trait BindExt<SI: SyntaxInterpreter> {
396 fn bind(&self, interpreter: SI) -> Generator<'_, SI>;
397}
398
399impl<SI: SyntaxInterpreter> BindExt<SI> for str {
400 fn bind(&self, interpreter: SI) -> Generator<'_, SI> {
401 Generator::new(self, interpreter)
402 }
403}
404
405type VariantName<'a> = &'a str;
406type VariantLiteral<'a> = &'a str;
407
408struct EnumInterpreter<'a> {
409 typ: &'a EnumType,
410 offset: usize,
411}
412
413impl<'a> EnumInterpreter<'a> {
414 fn with_offset(typ: &'a EnumType, offset: usize) -> Self {
415 Self { typ, offset }
416 }
417
418 fn interpret_subs(
419 &self,
420 subs: &EnumSubstitutions,
421 from_field: Option<&Field>,
422 code_buffer: &mut String,
423 ) -> Result<(), EnumInterpreterErr> {
424 let (accessor, enum_ref) = match from_field {
425 Some(field) => (format!(".{}", field.rust_name), self.typ.name.as_str()),
426 None => (String::new(), "Self"),
427 };
428
429 let offset = self.offset;
430
431 bufwriteln!(code_buffer, :>offset, "match self{accessor} {{");
432 for (var_name, literal) in self.variant_substitutions(subs)? {
433 bufwriteln!(code_buffer, :>offset + 4, "{enum_ref}::{var_name} => {{");
434 interpret_literal(literal, offset + 8, code_buffer);
435 bufwriteln!(code_buffer, :>offset + 4, "}}");
436 }
437 bufwriteln!(code_buffer, :>offset, "}}");
438 Ok(())
439 }
440
441 fn variant_substitutions<'s>(
442 &self,
443 enum_subs: &'s EnumSubstitutions<'s>,
444 ) -> Result<impl Iterator<Item = (VariantName<'a>, VariantLiteral<'s>)>, EnumInterpreterErr>
445 {
446 let literals_count = enum_subs.iter().count();
447
448 if self.typ.variants.len() != enum_subs.iter().count() {
449 return Err(EnumInterpreterErr {
450 expected: self.typ.variants.len(),
451 got: literals_count,
452 });
453 }
454
455 Ok(self
456 .typ
457 .variants
458 .iter()
459 .map(|var| var.rust_name.as_str())
460 .zip(enum_subs.iter()))
461 }
462}
463
464impl<'this> SyntaxInterpreter for EnumInterpreter<'this> {
465 type Error = EnumInterpreterErr;
466 type ContextData = ();
467
468 fn interpret_literal<'a>(
469 &mut self,
470 _el: SyntaxElement<'a>,
471 lit: &'a str,
472 _ctx: Option<&mut Self::ContextData>,
473 out: &mut String,
474 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
475 interpret_literal(lit, self.offset, out);
476 Ok(())
477 }
478
479 fn interpret_enum_substitutions<'a>(
480 &mut self,
481 _el: SyntaxElement<'a>,
482 enum_subs: EnumSubstitutions<'a>,
483 _ctx: Option<&mut Self::ContextData>,
484 out: &mut String,
485 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
486 self.interpret_subs(&enum_subs, None, out)
487 .map_err(SyntaxInterpreterError::Custom)?;
488
489 Ok(())
490 }
491}
492
493pub struct EnumInterpreterErr {
494 expected: usize,
495 got: usize,
496}
497
498impl std::fmt::Display for EnumInterpreterErr {
499 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
500 writeln!(
501 f,
502 "The enum has only {} variants, while the syntax defines {}",
503 self.expected, self.got
504 )
505 }
506}
507
508struct RecordInterpreter<'a> {
509 typ: &'a RecordType,
510 curr_field_ix: usize,
511 offset: usize,
512}
513
514impl<'a> RecordInterpreter<'a> {
515 fn with_offset(typ: &'a RecordType, offset: usize) -> Self {
516 Self {
517 typ,
518 curr_field_ix: 0,
519 offset,
520 }
521 }
522
523 fn current_field<'el>(
524 &self,
525 el: SyntaxElement<'el>,
526 ) -> SyntaxInterpreterResult<'el, &'a Field, String> {
527 self
528 .typ
529 .fields
530 .get(self.curr_field_ix)
531 .ok_or_else(|| {
532 SyntaxInterpreterError::Custom(format!("Expected a field while processing an element {el:?} but found None(current_field_ix={})", self.curr_field_ix))
533 })
534 }
535
536 fn field_by_api_name<'el>(
537 &mut self,
538 api_name: &str,
539 el: SyntaxElement<'el>,
540 ) -> SyntaxInterpreterResult<'el, &'a Field, String> {
541 loop {
542 let field = self.typ.fields.get(self.curr_field_ix).ok_or_else(|| {
543 SyntaxInterpreterError::Custom(format!("Failed to find a struct field with the name: {api_name:?} while trying to match element {el:?}"))
544 })?;
545
546 if field.api_name == api_name {
547 return Ok(field);
548 }
549
550 self.curr_field_ix += 1;
551 }
552 }
553}
554
555impl<'this> SyntaxInterpreter for RecordInterpreter<'this> {
556 type Error = String;
557 type ContextData = RecordContextData<'this>;
558
559 fn interpret_literal<'a>(
560 &mut self,
561 _el: SyntaxElement<'a>,
562 lit: &'a str,
563 ctx: Option<&mut Self::ContextData>,
564 out: &mut String,
565 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
566 match ctx {
567 Some(frame) => interpret_literal(lit, self.offset, &mut frame.buffer),
568 None => interpret_literal(lit, self.offset, out),
569 }
570
571 Ok(())
572 }
573
574 fn interpret_bool<'a>(
575 &mut self,
576 el: SyntaxElement<'a>,
577 maybe_bool: MaybeBool,
578 ctx: Option<&mut Self::ContextData>,
579 out: &mut String,
580 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
581 match maybe_bool {
582 MaybeBool::On | MaybeBool::Off => {
583 if let Some(frame) = ctx {
584 let maybe_bool_field = self.current_field(el)?;
585
586 if !maybe_bool_field.is_bool() {
587 return Err(SyntaxInterpreterError::Custom(format!(
588 "Expected a regular bool field but got {maybe_bool:?} while processing an element {el:?} in the optional span"
589 )));
590 }
591 if maybe_bool == MaybeBool::On {
592 interpret_literal("on", self.offset, &mut frame.buffer);
593 frame.cond_kind = CondKind::Bool(maybe_bool_field);
594 } else {
595 interpret_literal("off", self.offset, &mut frame.buffer);
596 frame.cond_kind = CondKind::NotBool(maybe_bool_field);
597 }
598 } else {
599 return Err(SyntaxInterpreterError::Custom(
600 "Unexpexted non-optional '{val:?}' literal that doesn't provide a choice. Expected (on|off)"
601 .to_owned(),
602 ));
603 }
604 }
605 MaybeBool::Either => {
606 let bool_field = self.current_field(el)?;
607
608 let (self_str, deref, dest) = if let Some(frame) = ctx {
609 if !bool_field.is_optional() {
610 return Err(SyntaxInterpreterError::Custom(format!(
611 "Expected an optional bool field but got {bool_field:?} while processing an element {el:?}"
612 )));
613 }
614
615 frame.cond_kind = CondKind::Opt(bool_field);
616 ("", "*", &mut frame.buffer)
617 } else {
618 if !bool_field.is_bool() {
619 return Err(SyntaxInterpreterError::Custom(format!(
620 "The current field must be a bool, but instead it's a {bool_field:?} for element {el:?}",
621 )));
622 }
623
624 ("self.", "", out)
625 };
626
627 bufwriteln!(dest, :> self.offset, "if {deref}{self_str}{} {{", bool_field.rust_name);
628 interpret_literal("on", self.offset + 4, dest);
629 bufwriteln!(dest, :> self.offset, "}} else {{");
630 interpret_literal("off", self.offset + 4, dest);
631 bufwriteln!(dest, :> self.offset, "}}");
632 }
633 }
634
635 self.curr_field_ix += 1;
636 Ok(())
637 }
638
639 fn interpret_enum_substitutions<'a>(
640 &mut self,
641 el: SyntaxElement<'a>,
642 enum_subs: EnumSubstitutions<'a>,
643 ctx: Option<&mut Self::ContextData>,
644 out: &mut String,
645 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
646 if ctx.is_some() {
647 return Err(SyntaxInterpreterError::Custom(format!(
649 "Enum substitutions are unsupported in optional contexts, but got {el:?}",
650 )));
651 }
652
653 let field = self.current_field(el)?;
654
655 if !field.is_compound() {
656 return Err(SyntaxInterpreterError::Custom(format!(
657 "Expected a enum field but got a {:?} field while processing {el:?}",
658 field.typ,
659 )));
660 }
661
662 let ad_hoc_enum = EnumType::new(
663 field.typ.clone(),
664 enum_subs.iter().map(EnumVariant::from_api_name).collect(),
665 );
666
667 let interpreter = EnumInterpreter::with_offset(&ad_hoc_enum, self.offset);
668 interpreter
669 .interpret_subs(&enum_subs, Some(field), out)
670 .map_err(|e| SyntaxInterpreterError::Custom(e.to_string()))?;
671
672 self.curr_field_ix += 1;
673 Ok(())
674 }
675
676 fn interpret_trivial_substitution<'a>(
677 &mut self,
678 el: SyntaxElement<'a>,
679 member_to_sub: &'a str,
680 ctx: Option<&mut Self::ContextData>,
681 out: &mut String,
682 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
683 let field = self.field_by_api_name(member_to_sub, el)?;
684
685 let (self_str, unwrap, dest) = match ctx {
686 Some(frame) => {
687 frame.cond_kind = CondKind::Opt(field);
688 ("", "", &mut frame.buffer)
689 }
690 None => ("self.", maybe_unwrap(field), out),
691 };
692
693 bufwriteln!(dest, :> self.offset, "write!(buf, \"{{}}\", {self_str}{}{unwrap}).unwrap();", field.rust_name);
694
695 self.curr_field_ix += 1;
696 Ok(())
697 }
698
699 fn interpret_delegate_substitution<'a>(
700 &mut self,
701 el: SyntaxElement<'a>,
702 member_to_sub: &'a str,
703 ctx: Option<&mut Self::ContextData>,
704 out: &mut String,
705 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
706 let field = self.field_by_api_name(member_to_sub, el)?;
707
708 let (self_str, dest) = match ctx {
709 Some(frame) => {
710 frame.cond_kind = CondKind::Opt(field);
711 ("", &mut frame.buffer)
712 }
713 None => ("self.", out),
714 };
715
716 bufwriteln!(dest, :> self.offset, "{self_str}{}.append_command_syntax(buf);", field.rust_name);
717
718 self.curr_field_ix += 1;
719 Ok(())
720 }
721
722 fn interpret_json_substitution<'a>(
723 &mut self,
724 el: SyntaxElement<'a>,
725 member_to_sub: &'a str,
726 ctx: Option<&mut Self::ContextData>,
727 out: &mut String,
728 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
729 let field = self.field_by_api_name(member_to_sub, el)?;
730
731 let (self_str, dest) = match ctx {
732 Some(frame) => {
733 frame.cond_kind = CondKind::Opt(field);
734 ("", &mut frame.buffer)
735 }
736 None => ("self.", out),
737 };
738
739 bufwriteln!(
740 dest,
741 :> self.offset, "// SAFETY: serde_json guarantees to produce valid UTF-8 sequences",
742 );
743 bufwriteln!(
744 dest,
745 :> self.offset, "unsafe {{ serde_json::to_writer(buf.as_mut_vec(), &{self_str}{}).unwrap(); }}",
746 field.rust_name,
747 );
748
749 self.curr_field_ix += 1;
750 Ok(())
751 }
752
753 fn interpret_vec_substitution<'a>(
754 &mut self,
755 el: SyntaxElement<'a>,
756 member_to_sub: &'a str,
757 delim: &'a str,
758 ctx: Option<&mut Self::ContextData>,
759 out: &mut String,
760 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
761 let field = self.field_by_api_name(member_to_sub, el)?;
762
763 let (self_str, unwrap, dest) = match ctx {
764 Some(frame) => {
765 frame.cond_kind = CondKind::Opt(field);
766 ("", "", &mut frame.buffer)
767 }
768 None => ("self.", maybe_unwrap(field), out),
769 };
770
771 bufwriteln!(dest, :> self.offset, "let mut iter = {self_str}{}{unwrap}.iter();", field.rust_name);
772 bufwriteln!(dest, :> self.offset, "if let Some(el) = iter.next() {{");
773 bufwriteln!(dest, :> self.offset + 4, "write!(buf, \"{{el}}\").unwrap();");
774 bufwriteln!(dest, :> self.offset, "}}");
775 bufwriteln!(dest, :> self.offset, "for el in iter {{");
776 interpret_literal(delim, self.offset + 4, dest);
777 bufwriteln!(dest, :> self.offset + 4, "write!(buf, \"{{el}}\").unwrap();");
778 bufwriteln!(dest, :> self.offset, "}}");
779
780 self.curr_field_ix += 1;
781 Ok(())
782 }
783
784 fn interpret_optional_context_enter<'a>(
785 &mut self,
786 _el: SyntaxElement<'a>,
787 _out: &mut String,
788 ) -> SyntaxInterpreterResult<'a, Self::ContextData, Self::Error> {
789 self.offset += 4;
790 Ok(RecordContextData {
791 buffer: String::with_capacity(256),
792 cond_kind: CondKind::None,
793 })
794 }
795
796 fn interpret_optional_context_exit<'a>(
797 &mut self,
798 el: SyntaxElement<'a>,
799 ctx: Self::ContextData,
800 out: &mut String,
801 ) -> SyntaxInterpreterResult<'a, (), Self::Error> {
802 self.offset -= 4;
803
804 match ctx.cond_kind {
805 CondKind::Bool(field) => {
806 bufwriteln!(out, :> self.offset, "if self.{} {{", field.rust_name);
807 }
808 CondKind::NotBool(field) => {
809 bufwriteln!(out, :> self.offset, "if !self.{} {{", field.rust_name);
810 }
811 CondKind::Opt(field) => {
812 bufwriteln!(out, :> self.offset, "if let Some({0}) = &self.{0} {{", field.rust_name);
813 }
814 CondKind::None => {
815 return Err(SyntaxInterpreterError::Custom(format!(
816 "Failed to deduce a field type in optional context while processing {el:?}"
817 )));
818 }
819 }
820
821 out.push_str(&ctx.buffer);
822
823 bufwriteln!(out, :> self.offset, "}}");
824 Ok(())
825 }
826}
827
828pub struct RecordContextData<'a> {
829 buffer: String,
830 cond_kind: CondKind<'a>,
831}
832
833enum CondKind<'a> {
834 Bool(&'a Field),
835 NotBool(&'a Field),
836 Opt(&'a Field),
837 None,
838}
839
840fn interpret_literal(literal: &str, offset: usize, code_buffer: &mut String) {
841 if literal.len() == 1 {
842 bufwriteln!(code_buffer, :>offset, "buf.push('{literal}');");
843 } else {
844 bufwriteln!(code_buffer, :>offset, "buf.push_str(\"{literal}\");");
845 }
846}
847
848fn maybe_unwrap(field: &Field) -> &'static str {
849 if let Some(inner) = field.inner_type() {
850 if field.is_optional() && types::is_string_type(inner) {
851 ".as_deref().unwrap_or_default()"
852 } else if field.is_vec() {
853 ""
854 } else {
855 ".unwrap_or_default()"
856 }
857 } else {
858 ""
859 }
860}
861
862#[cfg(test)]
863mod tests {
864 use super::*;
865 use expect_test::expect;
866
867 #[test]
868 fn enum_interpreter() {
869 let mut test_enum = EnumType::new(
870 "Greeting".to_owned(),
871 vec!["\"hi\"".parse().unwrap(), "\"bye\"".parse().unwrap()],
872 );
873
874 test_enum.syntax = "Hello,|Goodbye,| World!".to_owned();
875
876 let interpreter_impl = test_enum.command_syntax_impl().unwrap().unwrap();
877
878 expect![[r#"
879 impl CommandSyntax for Greeting {
880 const COMMAND_BUF_SIZE: usize = 16;
881
882 fn append_command_syntax(&self, buf: &mut String) {
883 match self {
884 Self::Hi => {
885 buf.push_str("Hello,");
886 }
887 Self::Bye => {
888 buf.push_str("Goodbye,");
889 }
890 }
891 buf.push(' ');
892 buf.push_str("World!");
893 }
894 }
895 "#]]
896 .assert_eq(&interpreter_impl);
897 }
898
899 trait CommandSyntax {
900 const COMMAND_BUF_SIZE: usize;
901
902 fn to_command_string(&self) -> String {
903 let mut buf = String::with_capacity(Self::COMMAND_BUF_SIZE);
904 self.append_command_syntax(&mut buf);
905 buf
906 }
907
908 fn append_command_syntax(&self, buf: &mut String);
909 }
910
911 enum Greeting {
912 Hi,
913 Bye,
914 }
915
916 impl CommandSyntax for Greeting {
917 const COMMAND_BUF_SIZE: usize = 16;
918 fn append_command_syntax(&self, buf: &mut String) {
919 match self {
920 Self::Hi => {
921 buf.push_str("Hello,");
922 }
923 Self::Bye => {
924 buf.push_str("Goodbye,");
925 }
926 }
927 buf.push(' ');
928 buf.push_str("World!");
929 }
930 }
931
932 #[test]
933 fn real_greeting() {
934 assert_eq!(Greeting::Hi.to_command_string(), "Hello, World!");
935 assert_eq!(Greeting::Bye.to_command_string(), "Goodbye, World!");
936 }
937}