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, "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
119pub trait SyntaxInterpreter {
130 type ContextData;
137
138 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 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 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 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
298pub 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
308pub 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
387pub 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 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}