1use crate::cst::TreeIter;
5use crate::ErrorAccumulator;
6
7use super::cst;
8use super::error::Error;
9use super::Str;
10use std::borrow::Cow;
11
12#[derive(Debug, PartialEq, Eq, Clone)]
16#[allow(clippy::large_enum_variant)]
17pub enum Vertical<'a> {
18 Hlist(Hlist<'a>),
19 Vlist(Vlist<'a>),
20 Glue(Glue<'a>),
21 Kern(Kern<'a>),
22 Penalty(Penalty<'a>),
23 Rule(Rule<'a>),
24 Mark(Mark<'a>),
25 Insertion(Insertion<'a>),
26 Math(Math<'a>),
27}
28
29#[derive(Debug, PartialEq, Eq, Clone)]
33pub enum Horizontal<'a> {
34 Chars(Chars<'a>),
35 Glue(Glue<'a>),
36 Penalty(Penalty<'a>),
37 Kern(Kern<'a>),
38 Hlist(Hlist<'a>),
39 Vlist(Vlist<'a>),
40 Ligature(Ligature<'a>),
41 Discretionary(Discretionary<'a>),
42 Rule(Rule<'a>),
43 Mark(Mark<'a>),
44 Adjust(Adjust<'a>),
45 Insertion(Insertion<'a>),
46 Math(Math<'a>),
47}
48
49impl<'a> From<Chars<'a>> for Horizontal<'a> {
50 fn from(value: Chars<'a>) -> Self {
51 Horizontal::Chars(value)
52 }
53}
54
55#[derive(Debug, PartialEq, Eq, Clone)]
59pub enum DiscretionaryElem<'a> {
60 Chars(Chars<'a>),
61 Kern(Kern<'a>),
62 Hlist(Hlist<'a>),
63 Vlist(Vlist<'a>),
64 Ligature(Ligature<'a>),
65 Rule(Rule<'a>),
66}
67
68pub fn lower_hlist<'a, 'b>(list: &'b [Horizontal<'a>]) -> impl cst::TreeIter<'a> + 'b {
70 lower_hlist_impl(list)
71}
72
73fn lower_hlist_impl<'a, 'b>(list: &'b [Horizontal<'a>]) -> CstTreeIter<'a, 'b> {
74 CstTreeIter::Hlist { list, next: 0 }
75}
76
77pub fn lower_vlist<'a, 'b>(list: &'b [Vertical<'a>]) -> impl cst::TreeIter<'a> + 'b {
79 lower_vlist_impl(list)
80}
81
82fn lower_vlist_impl<'a, 'b>(list: &'b [Vertical<'a>]) -> CstTreeIter<'a, 'b> {
83 CstTreeIter::Vlist { list, next: 0 }
84}
85
86fn lower_dlist_impl<'a, 'b>(list: &'b [DiscretionaryElem<'a>]) -> CstTreeIter<'a, 'b> {
87 CstTreeIter::Dlist { list, next: 0 }
88}
89
90impl<'a> Horizontal<'a> {
91 pub fn lower<'b>(&'b self) -> impl cst::TreeIter<'a> + 'b {
93 lower_hlist(std::slice::from_ref(self))
94 }
95 pub fn lower_args<'b>(&'b self) -> impl cst::ArgsIter<'a> + 'b {
97 self.lower_args_impl()
98 }
99 fn lower_args_impl<'b>(&'b self) -> CstArgsIter<'a, 'b> {
100 CstArgsIter::Hlist {
101 elem: self,
102 next: 0,
103 }
104 }
105}
106
107impl<'a> Vertical<'a> {
108 pub fn lower<'b>(&'b self) -> impl cst::TreeIter<'a> + 'b {
110 lower_vlist(std::slice::from_ref(self))
111 }
112 pub fn lower_args<'b>(&'b self) -> impl cst::ArgsIter<'a> + 'b {
114 self.lower_args_impl()
115 }
116 fn lower_args_impl<'b>(&'b self) -> CstArgsIter<'a, 'b> {
117 CstArgsIter::Vlist {
118 elem: self,
119 next: 0,
120 }
121 }
122}
123
124impl<'a> DiscretionaryElem<'a> {
125 pub fn lower<'b>(&'b self) -> impl cst::TreeIter<'a> + 'b {
127 lower_dlist_impl(std::slice::from_ref(self))
128 }
129 pub fn lower_args<'b>(&'b self) -> impl cst::ArgsIter<'a> + 'b {
131 self.lower_args_impl()
132 }
133 fn lower_args_impl<'b>(&'b self) -> CstArgsIter<'a, 'b> {
134 CstArgsIter::Dlist {
135 elem: self,
136 next: 0,
137 }
138 }
139}
140
141enum CstTreeIter<'a, 'b> {
142 Hlist {
143 list: &'b [Horizontal<'a>],
144 next: usize,
145 },
146 Vlist {
147 list: &'b [Vertical<'a>],
148 next: usize,
149 },
150 Dlist {
151 list: &'b [DiscretionaryElem<'a>],
152 next: usize,
153 },
154}
155
156enum CstArgsIter<'a, 'b> {
157 Hlist {
158 elem: &'b Horizontal<'a>,
159 next: usize,
160 },
161 Vlist {
162 elem: &'b Vertical<'a>,
163 next: usize,
164 },
165 Dlist {
166 elem: &'b DiscretionaryElem<'a>,
167 next: usize,
168 },
169}
170
171impl<'a, 'b> Iterator for CstTreeIter<'a, 'b> {
172 type Item = cst::TreeItem<'a, CstArgsIter<'a, 'b>>;
173
174 fn next(&mut self) -> Option<Self::Item> {
175 match self {
176 CstTreeIter::Hlist { list, next } => {
177 let h = list.get(*next)?;
178 *next += 1;
179 Some(cst::TreeItem::FuncCall {
180 func_name: h.func_name().into(),
181 args: h.lower_args_impl(),
182 })
183 }
184 CstTreeIter::Vlist { list, next } => {
185 let h = list.get(*next)?;
186 *next += 1;
187 Some(cst::TreeItem::FuncCall {
188 func_name: h.func_name().into(),
189 args: h.lower_args_impl(),
190 })
191 }
192 CstTreeIter::Dlist { list, next } => {
193 let h = list.get(*next)?;
194 *next += 1;
195 Some(cst::TreeItem::FuncCall {
196 func_name: h.func_name().into(),
197 args: h.lower_args_impl(),
198 })
199 }
200 }
201 }
202}
203
204impl<'a, 'b> cst::TreeIter<'a> for CstTreeIter<'a, 'b> {
205 type ArgsIter = CstArgsIter<'a, 'b>;
206 fn remaining_source(&self) -> Str<'a> {
207 "".into()
208 }
209}
210
211impl<'a, 'b> Iterator for CstArgsIter<'a, 'b> {
212 type Item = cst::ArgsItem<'a, CstTreeIter<'a, 'b>>;
213
214 fn next(&mut self) -> Option<Self::Item> {
215 match self {
216 CstArgsIter::Hlist { elem, next } => {
217 let l = elem.lower_arg(*next)?;
218 *next += 1;
219 Some(l)
220 }
221 CstArgsIter::Vlist { elem, next } => {
222 let l = elem.lower_arg(*next)?;
223 *next += 1;
224 Some(l)
225 }
226 CstArgsIter::Dlist { elem, next } => {
227 let l = elem.lower_arg(*next)?;
228 *next += 1;
229 Some(l)
230 }
231 }
232 }
233}
234
235impl<'a, 'b> cst::ArgsIter<'a> for CstArgsIter<'a, 'b> {
236 type TreeIter = CstTreeIter<'a, 'b>;
237}
238
239impl<'a> std::fmt::Display for Horizontal<'a> {
240 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
241 cst::pretty_print(f, self.lower())
242 }
243}
244
245pub fn parse_hlist(source: &str) -> Result<Vec<Horizontal<'_>>, Vec<Error<'_>>> {
247 let errs: ErrorAccumulator = Default::default();
248 let calls = cst::parse(source, errs.clone());
249 let v = parse_hlist_using_cst(calls, &errs);
250 errs.check()?;
251 Ok(v)
252}
253
254pub fn parse_hlist_using_cst<'a>(
256 cst: impl cst::TreeIter<'a>,
257 errs: &ErrorAccumulator<'a>,
258) -> Vec<Horizontal<'a>> {
259 let mut v: Vec<Horizontal> = vec![];
260 for call in cst {
261 match call {
262 cst::TreeItem::FuncCall { func_name, args } => {
263 if let Some(elem) = convert_call_to_hlist_elem(func_name, args, errs) {
264 v.push(elem);
265 }
266 }
267 cst::TreeItem::Comment { value: _ } => continue,
268 }
269 }
270 v
271}
272
273pub fn parse_vlist_using_cst<'a>(
275 cst: impl cst::TreeIter<'a>,
276 errs: &ErrorAccumulator<'a>,
277) -> Vec<Vertical<'a>> {
278 let mut v: Vec<Vertical> = vec![];
279 for call in cst {
280 match call {
281 cst::TreeItem::FuncCall { func_name, args } => {
282 if let Some(elem) = convert_call_to_vlist_elem(func_name, args, errs) {
283 v.push(elem);
284 }
285 }
286 cst::TreeItem::Comment { value: _ } => continue,
287 }
288 }
289 v
290}
291
292fn parse_dlist_using_cst<'a>(
294 cst: impl cst::TreeIter<'a>,
295 errs: &ErrorAccumulator<'a>,
296) -> Vec<DiscretionaryElem<'a>> {
297 let mut v: Vec<DiscretionaryElem> = vec![];
298 for call in cst {
299 match call {
300 cst::TreeItem::FuncCall { func_name, args } => {
301 if let Some(elem) = convert_call_to_dlist_elem(func_name, args, errs) {
302 v.push(elem);
303 }
304 }
305 cst::TreeItem::Comment { value: _ } => continue,
306 }
307 }
308 v
309}
310
311macro_rules! functions {
312 ( $( (
313 struct $name: ident <$lifetime: lifetime> {
314 $(
315 $field_name: ident : $field_type: ty,
316 )+
317 }
318 impl Func {
319 func_name: $func_name: expr,
320 default_num_pos_arg: $default_num_pos_arg: expr,
321 }
322 $(
323 impl Horizontal {
324 variant: $horizontal_variant: ident,
325 }
326 )?
327 $(
328 impl Vertical {
329 variant: $vertical_variant: ident,
330 }
331 )?
332 $(
333 impl DiscretionaryElem {
334 variant: $discretionary_variant: ident,
335 }
336 )?
337 ), )+ ) => {
338 $(
339 #[derive(Debug, Default, PartialEq, Eq, Clone)]
340 pub struct $name <$lifetime> {
341 $(
342 pub $field_name : Arg<$lifetime, $field_type>,
343 )+
344 }
345 impl<$lifetime> Func for $name <$lifetime> {
346 const NAME: &'static str = "todo";
347 const FIELD_NAMES: &'static[&'static str] = &[ $( stringify!($field_name), )+];
348 const DEFAULT_NUM_POS_ARG: usize = $default_num_pos_arg;
349 }
350 impl<$lifetime> Args<$lifetime> for $name <$lifetime> {
351 fn assign_to_field<T: cst::TreeIter<$lifetime>>(&mut self, field_name: Str<$lifetime>, arg: cst::ArgsItem<$lifetime, T>, func_name: Str<$lifetime>, value_source: Str<$lifetime>, errs: &ErrorAccumulator<$lifetime>)
352 {
353 match field_name.str() {
354 $(
355 stringify!($field_name) => {
356 self.$field_name.assign(arg, field_name.str(), func_name, value_source, errs);
357 }
358 )+
359 _ => {
360 errs.add(Error::NoSuchArgument{function_name: func_name, argument: field_name });
361 }
362 }
363 }
364 fn lower_arg<'b>(&'b self, u: usize) -> Option<cst::ArgsItem<'a, CstTreeIter<'a, 'b>>> {
365 let field_name = *Self::FIELD_NAMES.get(u)?;
366 match field_name {
367 $(
368 stringify!($field_name) => {
369 let key = if u < Self::DEFAULT_NUM_POS_ARG {
370 None
371 } else {
372 Some(field_name.into())
373 };
374 Some(value_to_cst(&self.$field_name.value, key))
375 }
376 )+
377 _ => None,
378 }
379 }
380 }
381 )+
382 impl<'a> Horizontal<'a> {
383 pub fn func_name(&self) -> &'static str {
384 match self {
385 $( $(
386 Horizontal::$horizontal_variant(_) => $func_name,
387 )? )+
388 }
389 }
390 pub fn field_names(&self) -> &'static [&'static str ] {
391 match self {
392 $( $(
393 Horizontal::$horizontal_variant(_) => $name::FIELD_NAMES,
394 )? )+
395 }
396 }
397 fn lower_arg<'b>(&'b self, u: usize) -> Option<cst::ArgsItem<'a, CstTreeIter<'a, 'b>>> {
398 match self {
399 $( $(
400 Horizontal::$horizontal_variant(args) => args.lower_arg(u),
401 )? )+
402 }
403 }
404 }
405 fn convert_call_to_hlist_elem<'a>(
406 func_name: Str<'a>,
407 call: impl cst::ArgsIter<'a>,
408 errs: &ErrorAccumulator<'a>,
409 ) -> Option<Horizontal<'a>> {
410 let h = match func_name.str() {
411 $( $(
412 $func_name => Horizontal::$horizontal_variant($name::build(func_name, call, errs)?),
413 )? )+
414 _ => {
415 errs.add(Error::NoSuchFunction {
416 function_name: func_name,
417 });
418 return None;
419 }
420 };
421 Some(h)
422 }
423 impl<'a> DiscretionaryElem<'a> {
424 pub fn func_name(&self) -> &'static str {
425 match self {
426 $( $(
427 DiscretionaryElem::$discretionary_variant(_) => $func_name,
428 )? )+
429 }
430 }
431 pub fn field_names(&self) -> &'static [&'static str ] {
432 match self {
433 $( $(
434 DiscretionaryElem::$discretionary_variant(_) => $name::FIELD_NAMES,
435 )? )+
436 }
437 }
438 fn lower_arg<'b>(&'b self, u: usize) -> Option<cst::ArgsItem<'a, CstTreeIter<'a, 'b>>> {
439 match self {
440 $( $(
441 DiscretionaryElem::$discretionary_variant(args) => args.lower_arg(u),
442 )? )+
443 }
444 }
445 }
446 fn convert_call_to_dlist_elem<'a>(
447 func_name: Str<'a>,
448 call: impl cst::ArgsIter<'a>,
449 errs: &ErrorAccumulator<'a>,
450 ) -> Option<DiscretionaryElem<'a>> {
451 let d = match func_name.str() {
452 $( $(
453 $func_name => DiscretionaryElem::$discretionary_variant($name::build(func_name, call, errs)?),
454 )? )+
455 _ => {
456 errs.add(Error::NoSuchFunction {
457 function_name: func_name,
458 });
459 return None;
460 }
461 };
462 Some(d)
463 }
464 impl<'a> Vertical<'a> {
465 pub fn func_name(&self) -> &'static str {
466 match self {
467 $( $(
468 Vertical::$vertical_variant(_) => $func_name,
469 )? )+
470 }
471 }
472 pub fn field_names(&self) -> &'static [&'static str ] {
473 match self {
474 $( $(
475 Vertical::$vertical_variant(_) => $name::FIELD_NAMES,
476 )? )+
477 }
478 }
479 fn lower_arg<'b>(&'b self, u: usize) -> Option<cst::ArgsItem<'a, CstTreeIter<'a, 'b>>> {
480 match self {
481 $( $(
482 Vertical::$vertical_variant(args) => args.lower_arg(u),
483 )? )+
484 }
485 }
486 }
487 fn convert_call_to_vlist_elem<'a>(
488 func_name: Str<'a>,
489 call: impl cst::ArgsIter<'a>,
490 errs: &ErrorAccumulator<'a>,
491 ) -> Option<Vertical<'a>> {
492 let h = match func_name.str() {
493 $( $(
494 $func_name => Vertical::$vertical_variant($name::build(func_name, call, errs)?),
495 )? )+
496 _ => {
497 errs.add(Error::NoSuchFunction {
498 function_name: func_name,
499 });
500 return None;
501 }
502 };
503 Some(h)
504 }
505 };
506}
507
508pub trait Func {
510 const NAME: &'static str;
512 const FIELD_NAMES: &'static [&'static str];
514 const DEFAULT_NUM_POS_ARG: usize = 0;
516}
517
518trait Args<'a>: Func + Default {
520 fn assign_to_field<T: cst::TreeIter<'a>>(
521 &mut self,
522 field_name: Str<'a>,
523 arg: cst::ArgsItem<'a, T>,
524 func_name: Str<'a>,
525 value_source: Str<'a>,
526 errs: &ErrorAccumulator<'a>,
527 );
528
529 fn build(
530 func_name: Str<'a>,
531 args: impl cst::ArgsIter<'a>,
532 errs: &ErrorAccumulator<'a>,
533 ) -> Option<Self> {
534 let mut p: Self = Default::default();
535 let start = errs.len();
536 let mut field_names = Self::FIELD_NAMES.iter();
537 let mut last_keyword_arg: Option<Str> = None;
538 for arg in args {
539 let (key, value_source) = match &arg {
540 cst::ArgsItem::Regular {
541 key,
542 value: _,
543 value_source,
544 } => (key, value_source.clone()),
545 cst::ArgsItem::List {
546 key,
547 square_open: _,
548 tree,
549 } => (key, tree.remaining_source()),
550 cst::ArgsItem::Comment { .. } => continue,
551 };
552 let field_name = match key {
553 None => {
555 if let Some(keyword_arg) = &last_keyword_arg {
556 errs.add(Error::PositionalArgAfterKeywordArg {
557 positional_arg: value_source,
558 keyword_arg: keyword_arg.clone(),
559 });
560 continue;
561 }
562 let Some(field_name) = field_names.next() else {
563 errs.add(Error::TooManyPositionalArgs {
564 extra_positional_arg: value_source,
565 function_name: func_name.clone(),
566 max_positional_args: Self::FIELD_NAMES.len(),
567 });
568 continue;
569 };
570 Str::new(field_name)
571 }
572 Some(field_name) => {
574 last_keyword_arg = Some(Str {
575 end: value_source.end,
576 ..*field_name
577 });
578 field_name.clone()
579 }
580 };
581 p.assign_to_field(field_name, arg, func_name.clone(), value_source, errs);
582 }
583 if errs.len() == start {
584 Some(p)
585 } else {
586 None
587 }
588 }
589
590 fn lower_arg<'b>(&'b self, i: usize) -> Option<cst::ArgsItem<'a, CstTreeIter<'a, 'b>>>;
592}
593
594functions!(
595 (
596 struct Chars<'a> {
597 content: Cow<'a, str>,
598 font: i32,
599 }
600 impl Func {
601 func_name: "chars",
602 default_num_pos_arg: 1,
603 }
604 impl Horizontal {
605 variant: Chars,
606 }
607 impl DiscretionaryElem {
608 variant: Chars,
609 }
610 ),
611 (
612 struct Glue<'a> {
613 width: core::Scaled,
614 stretch: (core::Scaled, core::GlueOrder),
615 shrink: (core::Scaled, core::GlueOrder),
616 }
617 impl Func {
618 func_name: "glue",
619 default_num_pos_arg: 3,
620 }
621 impl Horizontal {
622 variant: Glue,
623 }
624 impl Vertical {
625 variant: Glue,
626 }
627 ),
628 (
629 struct Penalty<'a> {
630 value: i32,
631 }
632 impl Func {
633 func_name: "penalty",
634 default_num_pos_arg: 1,
635 }
636 impl Horizontal {
637 variant: Penalty,
638 }
639 impl Vertical {
640 variant: Penalty,
641 }
642 ),
643 (
644 struct Kern<'a> {
645 width: core::Scaled,
646 }
647 impl Func {
648 func_name: "kern",
649 default_num_pos_arg: 1,
650 }
651 impl Horizontal {
652 variant: Kern,
653 }
654 impl Vertical {
655 variant: Kern,
656 }
657 impl DiscretionaryElem {
658 variant: Kern,
659 }
660 ),
661 (
662 struct Hlist<'a> {
663 width: core::Scaled,
664 content: Vec<Horizontal<'a>>,
665 }
666 impl Func {
667 func_name: "hlist",
668 default_num_pos_arg: 0,
669 }
670 impl Horizontal {
671 variant: Hlist,
672 }
673 impl Vertical {
674 variant: Hlist,
675 }
676 impl DiscretionaryElem {
677 variant: Hlist,
678 }
679 ),
680 (
681 struct Ligature<'a> {
682 char: char,
683 original_chars: Cow<'a, str>,
684 font: i32,
685 }
686 impl Func {
687 func_name: "lig",
688 default_num_pos_arg: 2,
689 }
690 impl Horizontal {
691 variant: Ligature,
692 }
693 impl DiscretionaryElem {
694 variant: Ligature,
695 }
696 ),
697 (
698 struct Vlist<'a> {
699 content: Vec<Vertical<'a>>,
700 }
701 impl Func {
702 func_name: "vlist",
703 default_num_pos_arg: 0,
704 }
705 impl Horizontal {
706 variant: Vlist,
707 }
708 impl Vertical {
709 variant: Vlist,
710 }
711 impl DiscretionaryElem {
712 variant: Vlist,
713 }
714 ),
715 (
716 struct Discretionary<'a> {
717 pre_break: Vec<DiscretionaryElem<'a>>,
718 post_break: Vec<DiscretionaryElem<'a>>,
719 replace_count: i32,
720 }
721 impl Func {
722 func_name: "disc",
723 default_num_pos_arg: 0,
724 }
725 impl Horizontal {
726 variant: Discretionary,
727 }
728 ),
729 (
730 struct Rule<'a> {
731 height: core::Scaled,
732 width: core::Scaled,
733 depth: core::Scaled,
734 }
735 impl Func {
736 func_name: "rule",
737 default_num_pos_arg: 3,
738 }
739 impl Horizontal {
740 variant: Rule,
741 }
742 impl Vertical {
743 variant: Rule,
744 }
745 impl DiscretionaryElem {
746 variant: Rule,
747 }
748 ),
749 (
750 struct Mark<'a> {
751 dummy: i32,
752 }
753 impl Func {
754 func_name: "mark",
755 default_num_pos_arg: 0,
756 }
757 impl Horizontal {
758 variant: Mark,
759 }
760 impl Vertical {
761 variant: Mark,
762 }
763 ),
764 (
765 struct Adjust<'a> {
766 content: Vec<Vertical<'a>>,
767 }
768 impl Func {
769 func_name: "adjust",
770 default_num_pos_arg: 0,
771 }
772 impl Horizontal {
773 variant: Adjust,
774 }
775 ),
776 (
777 struct Insertion<'a> {
778 box_number: i32,
779 height: core::Scaled,
780 split_max_depth: core::Scaled,
781 split_top_skip_width: core::Scaled,
782 split_top_skip_stretch: (core::Scaled, core::GlueOrder),
783 split_top_skip_shrink: (core::Scaled, core::GlueOrder),
784 float_penalty: i32,
785 vlist: Vec<Vertical<'a>>,
786 }
787 impl Func {
788 func_name: "insertion",
789 default_num_pos_arg: 1,
790 }
791 impl Horizontal {
792 variant: Insertion,
793 }
794 impl Vertical {
795 variant: Insertion,
796 }
797 ),
798 (
799 struct Math<'a> {
800 kind: Cow<'a, str>,
801 }
802 impl Func {
803 func_name: "math",
804 default_num_pos_arg: 1,
805 }
806 impl Horizontal {
807 variant: Math,
808 }
809 impl Vertical {
810 variant: Math,
811 }
812 ),
813);
814
815#[derive(Debug, Default, PartialEq, Eq, Clone)]
817pub struct Arg<'a, T> {
818 pub value: T,
820 pub source: Option<Str<'a>>,
825}
826
827impl<'a, T> From<T> for Arg<'a, T> {
828 fn from(value: T) -> Self {
829 Arg {
830 value,
831 source: None,
832 }
833 }
834}
835
836#[allow(private_bounds)]
840impl<'a, T> Arg<'a, T>
841where
842 T: Value<'a>,
843{
844 fn assign<F: cst::TreeIter<'a>>(
845 &mut self,
846 arg: cst::ArgsItem<'a, F>,
847 field_name: &'a str,
848 func_name: Str<'a>,
849 value_source: Str<'a>,
850 errs: &ErrorAccumulator<'a>,
851 ) {
852 if let Some(first_assignment) = &self.source {
853 errs.add(Error::DuplicateArgument {
854 parameter_name: field_name,
855 first_assignment: first_assignment.clone(),
856 second_assignment: value_source,
857 });
858 return;
859 }
860 let (cast_result, value_type) = match arg {
861 cst::ArgsItem::Regular { value, .. } => match &value {
862 cst::Value::List(tree) => (T::try_cast_list(tree.iter(), errs), "a list"),
863 cst::Value::Integer(i) => (T::try_cast_integer(*i), "an integer"),
864 cst::Value::Scaled(scaled) => (T::try_cast_scaled(*scaled), "a number"),
865 cst::Value::InfiniteGlue(scaled, glue_order) => (
866 T::try_cast_infinite_glue(*scaled, *glue_order),
867 "an infinite glue",
868 ),
869 cst::Value::String(cow) => (T::try_cast_string(cow.clone()), "a string"),
870 },
871 cst::ArgsItem::List { tree, .. } => (T::try_cast_list(tree, errs), "a list"),
872 cst::ArgsItem::Comment { .. } => return,
873 };
874 match cast_result {
875 Some(val) => {
876 self.value = val;
877 self.source = Some(value_source);
878 }
879 None => errs.add(Error::IncorrectType {
880 wanted_type: T::DESCRIPTION,
881 got_type: value_type,
882 got_raw_value: value_source,
883 function_name: func_name,
884 parameter_name: field_name,
885 }),
886 }
887 }
888}
889
890trait Value<'a>: Sized {
895 const DESCRIPTION: &'static str;
896
897 fn try_cast_integer(_i: i32) -> Option<Self> {
898 None
899 }
900 fn try_cast_string(_s: Cow<'a, str>) -> Option<Self> {
901 None
902 }
903 fn try_cast_scaled(_s: core::Scaled) -> Option<Self> {
904 None
905 }
906 fn try_cast_infinite_glue(_s: core::Scaled, _o: core::GlueOrder) -> Option<Self> {
907 None
908 }
909 fn try_cast_list<F: cst::TreeIter<'a>>(
910 _value: F,
911 _errs: &ErrorAccumulator<'a>,
912 ) -> Option<Self> {
913 None
914 }
915
916 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>>;
917}
918
919impl<'a> Value<'a> for char {
920 const DESCRIPTION: &'static str = "a character";
921 fn try_cast_string(s: Cow<'a, str>) -> Option<Self> {
922 let mut iter = s.chars();
923 let c = iter.next()?;
924 match iter.next() {
925 Some(_) => None,
926 None => Some(c),
927 }
928 }
929 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
930 let s = format!("{self}");
931 cst::ArgsItem::Regular {
932 key,
933 value: cst::Value::String(s.into()),
934 value_source: "".into(),
935 }
936 }
937}
938
939impl<'a> Value<'a> for Cow<'a, str> {
940 const DESCRIPTION: &'static str = "a string";
941 fn try_cast_string(s: Cow<'a, str>) -> Option<Self> {
942 Some(s)
943 }
944 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
945 cst::ArgsItem::Regular {
946 key,
947 value: cst::Value::String(self.clone()),
948 value_source: "".into(),
949 }
950 }
951}
952
953impl<'a> Value<'a> for i32 {
954 const DESCRIPTION: &'static str = "an integer";
955 fn try_cast_integer(i: i32) -> Option<Self> {
956 Some(i)
957 }
958 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
959 cst::ArgsItem::Regular {
960 key,
961 value: cst::Value::Integer(*self),
962 value_source: "".into(),
963 }
964 }
965}
966
967impl<'a> Value<'a> for core::Scaled {
968 const DESCRIPTION: &'static str = "a number";
969 fn try_cast_scaled(s: core::Scaled) -> Option<Self> {
970 Some(s)
971 }
972 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
973 cst::ArgsItem::Regular {
974 key,
975 value: cst::Value::Scaled(*self),
976 value_source: "".into(),
977 }
978 }
979}
980
981impl<'a> Value<'a> for (core::Scaled, core::GlueOrder) {
982 const DESCRIPTION: &'static str = "a stretch or shrink glue component";
983 fn try_cast_scaled(s: core::Scaled) -> Option<Self> {
984 Some((s, core::GlueOrder::Normal))
985 }
986 fn try_cast_infinite_glue(s: core::Scaled, o: core::GlueOrder) -> Option<Self> {
987 Some((s, o))
988 }
989 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
990 cst::ArgsItem::Regular {
991 key,
992 value: cst::Value::InfiniteGlue(self.0, self.1),
993 value_source: "".into(),
994 }
995 }
996}
997
998impl<'a> Value<'a> for Vec<Vertical<'a>> {
999 const DESCRIPTION: &'static str = "a vlist";
1000 fn try_cast_list<F: cst::TreeIter<'a>>(value: F, errs: &ErrorAccumulator<'a>) -> Option<Self> {
1001 Some(parse_vlist_using_cst(value, errs))
1002 }
1003 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1004 cst::ArgsItem::List {
1005 key,
1006 square_open: "".into(),
1007 tree: lower_vlist_impl(self),
1008 }
1009 }
1010}
1011
1012impl<'a> Value<'a> for Vec<Horizontal<'a>> {
1013 const DESCRIPTION: &'static str = "a hlist";
1014 fn try_cast_list<F: cst::TreeIter<'a>>(value: F, errs: &ErrorAccumulator<'a>) -> Option<Self> {
1015 Some(parse_hlist_using_cst(value, errs))
1016 }
1017 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1018 cst::ArgsItem::List {
1019 key,
1020 square_open: "".into(),
1021 tree: lower_hlist_impl(self),
1022 }
1023 }
1024}
1025
1026impl<'a> Value<'a> for Vec<DiscretionaryElem<'a>> {
1027 const DESCRIPTION: &'static str = "a dlist";
1028 fn try_cast_list<F: cst::TreeIter<'a>>(value: F, errs: &ErrorAccumulator<'a>) -> Option<Self> {
1029 Some(parse_dlist_using_cst(value, errs))
1030 }
1031 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1032 cst::ArgsItem::List {
1033 key,
1034 square_open: "".into(),
1035 tree: lower_dlist_impl(self),
1036 }
1037 }
1038}
1039
1040fn value_to_cst<'a, 'b, V: Value<'a>>(
1041 value: &'b V,
1042 key: Option<Str<'a>>,
1043) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1044 value.lower(key)
1047}
1048
1049#[cfg(test)]
1050mod tests {
1051 use super::*;
1052 #[test]
1054 fn hlist() {
1055 let input = r#"
1056 hlist(
1057 width=1pt,
1058 content=[chars("Hello")],
1059 )
1060 "#;
1061
1062 let want = vec![Horizontal::Hlist(Hlist {
1063 width: Arg {
1064 value: core::Scaled::ONE.into(),
1065 source: Some("1pt".into()),
1066 },
1067 content: Arg {
1068 value: vec![Horizontal::Chars(Chars {
1069 content: Arg {
1070 value: "Hello".into(),
1071 source: Some(r#""Hello""#.into()),
1072 },
1073 font: Arg {
1074 value: 0,
1075 source: None,
1076 },
1077 ..Default::default()
1078 })],
1079 source: Some(r#"[chars("Hello")]"#.into()),
1080 },
1081 ..Default::default()
1082 })];
1083
1084 let got = parse_hlist(&input).expect("parsing succeeds");
1085
1086 assert_eq!(got, want);
1087 }
1088}