1use super::cst::TreeIter;
5use super::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 HBox(HBox<'a>),
19 VBox(VBox<'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 HBox(HBox<'a>),
39 VBox(VBox<'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 HBox(HBox<'a>),
63 VBox(VBox<'a>),
64 Ligature(Ligature<'a>),
65 Rule(Rule<'a>),
66}
67
68pub fn lower_hbox<'a, 'b>(list: &'b [Horizontal<'a>]) -> impl cst::TreeIter<'a> + 'b {
70 lower_hbox_impl(list)
71}
72
73fn lower_hbox_impl<'a, 'b>(list: &'b [Horizontal<'a>]) -> CstTreeIter<'a, 'b> {
74 CstTreeIter::H { list, next: 0 }
75}
76
77pub fn lower_vbox<'a, 'b>(list: &'b [Vertical<'a>]) -> impl cst::TreeIter<'a> + 'b {
79 lower_vbox_impl(list)
80}
81
82fn lower_vbox_impl<'a, 'b>(list: &'b [Vertical<'a>]) -> CstTreeIter<'a, 'b> {
83 CstTreeIter::V { list, next: 0 }
84}
85
86fn lower_dlist_impl<'a, 'b>(list: &'b [DiscretionaryElem<'a>]) -> CstTreeIter<'a, 'b> {
87 CstTreeIter::D { list, next: 0 }
88}
89
90impl<'a> Horizontal<'a> {
91 pub fn lower<'b>(&'b self) -> impl cst::TreeIter<'a> + 'b {
93 lower_hbox(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::H {
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_vbox(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::V {
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::D {
135 elem: self,
136 next: 0,
137 }
138 }
139}
140
141enum CstTreeIter<'a, 'b> {
142 H {
143 list: &'b [Horizontal<'a>],
144 next: usize,
145 },
146 V {
147 list: &'b [Vertical<'a>],
148 next: usize,
149 },
150 D {
151 list: &'b [DiscretionaryElem<'a>],
152 next: usize,
153 },
154 Other(&'b Horizontal<'a>),
155 Exausted,
156}
157
158enum CstArgsIter<'a, 'b> {
159 H {
160 elem: &'b Horizontal<'a>,
161 next: usize,
162 },
163 V {
164 elem: &'b Vertical<'a>,
165 next: usize,
166 },
167 D {
168 elem: &'b DiscretionaryElem<'a>,
169 next: usize,
170 },
171}
172
173impl<'a, 'b> Iterator for CstTreeIter<'a, 'b> {
174 type Item = cst::TreeItem<'a, CstArgsIter<'a, 'b>>;
175
176 fn next(&mut self) -> Option<Self::Item> {
177 match self {
178 CstTreeIter::H { list, next } => {
179 let h = list.get(*next)?;
180 *next += 1;
181 Some(cst::TreeItem::FuncCall {
182 func_name: h.func_name().into(),
183 args: h.lower_args_impl(),
184 })
185 }
186 CstTreeIter::V { list, next } => {
187 let h = list.get(*next)?;
188 *next += 1;
189 Some(cst::TreeItem::FuncCall {
190 func_name: h.func_name().into(),
191 args: h.lower_args_impl(),
192 })
193 }
194 CstTreeIter::D { list, next } => {
195 let h = list.get(*next)?;
196 *next += 1;
197 Some(cst::TreeItem::FuncCall {
198 func_name: h.func_name().into(),
199 args: h.lower_args_impl(),
200 })
201 }
202 CstTreeIter::Other(h) => {
203 let r = cst::TreeItem::FuncCall {
204 func_name: h.func_name().into(),
205 args: h.lower_args_impl(),
206 };
207 *self = CstTreeIter::Exausted;
208 Some(r)
209 }
210 CstTreeIter::Exausted => None,
211 }
212 }
213}
214
215impl<'a, 'b> cst::TreeIter<'a> for CstTreeIter<'a, 'b> {
216 type ArgsIter = CstArgsIter<'a, 'b>;
217 fn remaining_source(&self) -> Str<'a> {
218 "".into()
219 }
220}
221
222impl<'a, 'b> Iterator for CstArgsIter<'a, 'b> {
223 type Item = cst::ArgsItem<'a, CstTreeIter<'a, 'b>>;
224
225 fn next(&mut self) -> Option<Self::Item> {
226 match self {
227 CstArgsIter::H { elem, next } => {
228 let l = elem.lower_arg(*next)?;
230 *next += 1;
231 Some(l)
232 }
233 CstArgsIter::V { elem, next } => {
234 let l = elem.lower_arg(*next)?;
235 *next += 1;
236 Some(l)
237 }
238 CstArgsIter::D { elem, next } => {
239 let l = elem.lower_arg(*next)?;
240 *next += 1;
241 Some(l)
242 }
243 }
244 }
245}
246
247impl<'a, 'b> cst::ArgsIter<'a> for CstArgsIter<'a, 'b> {
248 type TreeIter = CstTreeIter<'a, 'b>;
249}
250
251impl<'a> std::fmt::Display for Vertical<'a> {
252 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
253 cst::pretty_print(f, self.lower())
254 }
255}
256
257impl<'a> std::fmt::Display for Horizontal<'a> {
258 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259 cst::pretty_print(f, self.lower())
260 }
261}
262
263pub fn parse_hbox(source: &str) -> Result<Vec<Horizontal<'_>>, Vec<Error<'_>>> {
265 let errs: ErrorAccumulator = Default::default();
266 let calls = cst::parse(source, errs.clone());
267 let v = parse_hbox_using_cst(calls, &errs);
268 errs.check()?;
269 Ok(v)
270}
271
272pub fn parse_hbox_using_cst<'a>(
274 cst: impl cst::TreeIter<'a>,
275 errs: &ErrorAccumulator<'a>,
276) -> Vec<Horizontal<'a>> {
277 let mut v: Vec<Horizontal> = vec![];
278 for call in cst {
279 match call {
280 cst::TreeItem::FuncCall { func_name, args } => {
281 if let Some(elem) = convert_call_to_hbox_elem(func_name, args, errs) {
282 v.push(elem);
283 }
284 }
285 cst::TreeItem::Comment { value: _ } => continue,
286 }
287 }
288 v
289}
290
291pub fn parse_vbox_using_cst<'a>(
293 cst: impl cst::TreeIter<'a>,
294 errs: &ErrorAccumulator<'a>,
295) -> Vec<Vertical<'a>> {
296 let mut v: Vec<Vertical> = vec![];
297 for call in cst {
298 match call {
299 cst::TreeItem::FuncCall { func_name, args } => {
300 if let Some(elem) = convert_call_to_vbox_elem(func_name, args, errs) {
301 v.push(elem);
302 }
303 }
304 cst::TreeItem::Comment { value: _ } => continue,
305 }
306 }
307 v
308}
309
310fn parse_dlist_using_cst<'a>(
312 cst: impl cst::TreeIter<'a>,
313 errs: &ErrorAccumulator<'a>,
314) -> Vec<DiscretionaryElem<'a>> {
315 let mut v: Vec<DiscretionaryElem> = vec![];
316 for call in cst {
317 match call {
318 cst::TreeItem::FuncCall { func_name, args } => {
319 if let Some(elem) = convert_call_to_dlist_elem(func_name, args, errs) {
320 v.push(elem);
321 }
322 }
323 cst::TreeItem::Comment { value: _ } => continue,
324 }
325 }
326 v
327}
328
329macro_rules! default_or {
332 () => {
333 Default::default()
334 };
335 ($default: expr) => {
336 $default
337 };
338}
339
340macro_rules! functions {
341 ( $( (
342 struct $name: ident <$lifetime: lifetime> {
343 $(
344 $field_name: ident : $field_type: ty $( = $field_default: expr)?,
345 )+
346 }
347 impl Func {
348 func_name: $func_name: expr,
349 default_num_pos_arg: $default_num_pos_arg: expr,
350 }
351 $(
352 impl Horizontal {
353 variant: $horizontal_variant: ident,
354 }
355 )?
356 $(
357 impl Vertical {
358 variant: $vertical_variant: ident,
359 }
360 )?
361 $(
362 impl DiscretionaryElem {
363 variant: $discretionary_variant: ident,
364 }
365 )?
366 ), )+ ) => {
367 $(
368 #[derive(Debug, PartialEq, Eq, Clone)]
369 pub struct $name <$lifetime> {
370 $(
371 pub $field_name : Arg<$lifetime, $field_type>,
372 )+
373 }
374 impl<$lifetime> Default for $name <$lifetime> {
375 fn default() -> Self {
376 Self {
377 $(
378 $field_name: {
379 let value: $field_type = default_or![$($field_default)?];
380 value.into()
381 },
382 )+
383 }
384 }
385 }
386 impl<$lifetime> Func for $name <$lifetime> {
387 const NAME: &'static str = "todo";
388 const FIELD_NAMES: &'static[&'static str] = &[ $( stringify!($field_name), )+];
389 const DEFAULT_NUM_POS_ARG: usize = $default_num_pos_arg;
390 }
391 impl<$lifetime> Args<$lifetime> for $name <$lifetime> {
392 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>)
393 {
394 match field_name.str() {
395 $(
396 stringify!($field_name) => {
397 self.$field_name.assign(arg, field_name.str(), func_name, value_source, errs);
398 }
399 )+
400 _ => {
401 errs.add(Error::NoSuchArgument{function_name: func_name, argument: field_name });
402 }
403 }
404 }
405 fn lower_arg<'b>(&'b self, u: usize) -> Option<cst::ArgsItem<'a, CstTreeIter<'a, 'b>>> {
406 let field_name = *Self::FIELD_NAMES.get(u)?;
407 match field_name {
408 $(
409 stringify!($field_name) => {
410 let key = if u < Self::DEFAULT_NUM_POS_ARG {
411 None
412 } else {
413 Some(field_name.into())
414 };
415 Some(value_to_cst(&self.$field_name.value, key))
416 }
417 )+
418 _ => None,
419 }
420 }
421 }
422 )+
423 impl<'a> Horizontal<'a> {
424 pub fn func_name(&self) -> &'static str {
425 match self {
426 $( $(
427 Horizontal::$horizontal_variant(_) => $func_name,
428 )? )+
429 }
430 }
431 pub fn field_names(&self) -> &'static [&'static str ] {
432 match self {
433 $( $(
434 Horizontal::$horizontal_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 Horizontal::$horizontal_variant(args) => args.lower_arg(u),
442 )? )+
443 }
444 }
445 }
446 fn convert_call_to_hbox_elem<'a>(
447 func_name: Str<'a>,
448 call: impl cst::ArgsIter<'a>,
449 errs: &ErrorAccumulator<'a>,
450 ) -> Option<Horizontal<'a>> {
451 let h = match func_name.str() {
452 $( $(
453 $func_name => Horizontal::$horizontal_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(h)
463 }
464 impl<'a> DiscretionaryElem<'a> {
465 pub fn func_name(&self) -> &'static str {
466 match self {
467 $( $(
468 DiscretionaryElem::$discretionary_variant(_) => $func_name,
469 )? )+
470 }
471 }
472 pub fn field_names(&self) -> &'static [&'static str ] {
473 match self {
474 $( $(
475 DiscretionaryElem::$discretionary_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 DiscretionaryElem::$discretionary_variant(args) => args.lower_arg(u),
483 )? )+
484 }
485 }
486 }
487 fn convert_call_to_dlist_elem<'a>(
488 func_name: Str<'a>,
489 call: impl cst::ArgsIter<'a>,
490 errs: &ErrorAccumulator<'a>,
491 ) -> Option<DiscretionaryElem<'a>> {
492 let d = match func_name.str() {
493 $( $(
494 $func_name => DiscretionaryElem::$discretionary_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(d)
504 }
505 impl<'a> Vertical<'a> {
506 pub fn func_name(&self) -> &'static str {
507 match self {
508 $( $(
509 Vertical::$vertical_variant(_) => $func_name,
510 )? )+
511 }
512 }
513 pub fn field_names(&self) -> &'static [&'static str ] {
514 match self {
515 $( $(
516 Vertical::$vertical_variant(_) => $name::FIELD_NAMES,
517 )? )+
518 }
519 }
520 fn lower_arg<'b>(&'b self, u: usize) -> Option<cst::ArgsItem<'a, CstTreeIter<'a, 'b>>> {
521 match self {
522 $( $(
523 Vertical::$vertical_variant(args) => args.lower_arg(u),
524 )? )+
525 }
526 }
527 }
528 fn convert_call_to_vbox_elem<'a>(
529 func_name: Str<'a>,
530 call: impl cst::ArgsIter<'a>,
531 errs: &ErrorAccumulator<'a>,
532 ) -> Option<Vertical<'a>> {
533 let h = match func_name.str() {
534 $( $(
535 $func_name => Vertical::$vertical_variant($name::build(func_name, call, errs)?),
536 )? )+
537 _ => {
538 errs.add(Error::NoSuchFunction {
539 function_name: func_name,
540 });
541 return None;
542 }
543 };
544 Some(h)
545 }
546 };
547}
548
549pub trait Func {
551 const NAME: &'static str;
553 const FIELD_NAMES: &'static [&'static str];
555 const DEFAULT_NUM_POS_ARG: usize = 0;
557}
558
559trait Args<'a>: Func + Default {
561 fn assign_to_field<T: cst::TreeIter<'a>>(
562 &mut self,
563 field_name: Str<'a>,
564 arg: cst::ArgsItem<'a, T>,
565 func_name: Str<'a>,
566 value_source: Str<'a>,
567 errs: &ErrorAccumulator<'a>,
568 );
569
570 fn build(
571 func_name: Str<'a>,
572 args: impl cst::ArgsIter<'a>,
573 errs: &ErrorAccumulator<'a>,
574 ) -> Option<Self> {
575 let mut p: Self = Default::default();
576 let start = errs.len();
577 let mut field_names = Self::FIELD_NAMES.iter();
578 let mut last_keyword_arg: Option<Str> = None;
579 for arg in args {
580 let (key, value_source) = match &arg {
581 cst::ArgsItem::Regular {
582 key,
583 value: _,
584 value_source,
585 } => (key, value_source.clone()),
586 cst::ArgsItem::List {
587 key,
588 square_open: _,
589 tree,
590 } => (key, tree.remaining_source()),
591 cst::ArgsItem::Comment { .. } => continue,
592 };
593 let field_name = match key {
594 None => {
596 if let Some(keyword_arg) = &last_keyword_arg {
597 errs.add(Error::PositionalArgAfterKeywordArg {
598 positional_arg: value_source,
599 keyword_arg: keyword_arg.clone(),
600 });
601 continue;
602 }
603 let Some(field_name) = field_names.next() else {
604 errs.add(Error::TooManyPositionalArgs {
605 extra_positional_arg: value_source,
606 function_name: func_name.clone(),
607 max_positional_args: Self::FIELD_NAMES.len(),
608 });
609 continue;
610 };
611 Str::new(field_name)
612 }
613 Some(field_name) => {
615 last_keyword_arg = Some(Str {
616 end: value_source.end,
617 ..*field_name
618 });
619 field_name.clone()
620 }
621 };
622 p.assign_to_field(field_name, arg, func_name.clone(), value_source, errs);
623 }
624 if errs.len() == start {
625 Some(p)
626 } else {
627 None
628 }
629 }
630
631 fn lower_arg<'b>(&'b self, i: usize) -> Option<cst::ArgsItem<'a, CstTreeIter<'a, 'b>>>;
633}
634
635functions!(
636 (
637 struct Chars<'a> {
638 content: Cow<'a, str>,
639 font: common::FontId = common::FontId::ONE,
640 }
641 impl Func {
642 func_name: "chars",
643 default_num_pos_arg: 1,
644 }
645 impl Horizontal {
646 variant: Chars,
647 }
648 impl DiscretionaryElem {
649 variant: Chars,
650 }
651 ),
652 (
653 struct Glue<'a> {
654 width: common::Scaled,
655 stretch: (common::Scaled, common::GlueOrder),
656 shrink: (common::Scaled, common::GlueOrder),
657 }
658 impl Func {
659 func_name: "glue",
660 default_num_pos_arg: 3,
661 }
662 impl Horizontal {
663 variant: Glue,
664 }
665 impl Vertical {
666 variant: Glue,
667 }
668 ),
669 (
670 struct Penalty<'a> {
671 value: i32,
672 }
673 impl Func {
674 func_name: "penalty",
675 default_num_pos_arg: 1,
676 }
677 impl Horizontal {
678 variant: Penalty,
679 }
680 impl Vertical {
681 variant: Penalty,
682 }
683 ),
684 (
685 struct Kern<'a> {
686 width: common::Scaled,
687 }
688 impl Func {
689 func_name: "kern",
690 default_num_pos_arg: 1,
691 }
692 impl Horizontal {
693 variant: Kern,
694 }
695 impl Vertical {
696 variant: Kern,
697 }
698 impl DiscretionaryElem {
699 variant: Kern,
700 }
701 ),
702 (
703 struct HBox<'a> {
704 height: common::Scaled,
705 width: common::Scaled,
706 depth: common::Scaled,
707 shift_amount: common::Scaled,
708 glue_ratio: crate::ds::GlueRatio,
709 glue_order: common::GlueOrder,
710 content: Vec<Horizontal<'a>>,
711 }
712 impl Func {
713 func_name: "hbox",
714 default_num_pos_arg: 0,
715 }
716 impl Horizontal {
717 variant: HBox,
718 }
719 impl Vertical {
720 variant: HBox,
721 }
722 impl DiscretionaryElem {
723 variant: HBox,
724 }
725 ),
726 (
727 struct Ligature<'a> {
728 char: char,
729 original_chars: Cow<'a, str>,
730 font: common::FontId = common::FontId::ONE,
731 includes_left_boundary: bool,
732 includes_right_boundary: bool,
733 }
734 impl Func {
735 func_name: "lig",
736 default_num_pos_arg: 2,
737 }
738 impl Horizontal {
739 variant: Ligature,
740 }
741 impl DiscretionaryElem {
742 variant: Ligature,
743 }
744 ),
745 (
746 struct VBox<'a> {
747 height: common::Scaled,
748 width: common::Scaled,
749 depth: common::Scaled,
750 shift_amount: common::Scaled,
751 content: Vec<Vertical<'a>>,
752 }
753 impl Func {
754 func_name: "vbox",
755 default_num_pos_arg: 0,
756 }
757 impl Horizontal {
758 variant: VBox,
759 }
760 impl Vertical {
761 variant: VBox,
762 }
763 impl DiscretionaryElem {
764 variant: VBox,
765 }
766 ),
767 (
768 struct Discretionary<'a> {
769 pre_break: Vec<DiscretionaryElem<'a>>,
770 post_break: Vec<DiscretionaryElem<'a>>,
771 replace_count: i32,
772 }
773 impl Func {
774 func_name: "disc",
775 default_num_pos_arg: 0,
776 }
777 impl Horizontal {
778 variant: Discretionary,
779 }
780 ),
781 (
782 struct Rule<'a> {
783 height: MaybeRunning,
784 width: MaybeRunning,
785 depth: MaybeRunning,
786 }
787 impl Func {
788 func_name: "rule",
789 default_num_pos_arg: 3,
790 }
791 impl Horizontal {
792 variant: Rule,
793 }
794 impl Vertical {
795 variant: Rule,
796 }
797 impl DiscretionaryElem {
798 variant: Rule,
799 }
800 ),
801 (
802 struct Mark<'a> {
803 dummy: i32,
804 }
805 impl Func {
806 func_name: "mark",
807 default_num_pos_arg: 0,
808 }
809 impl Horizontal {
810 variant: Mark,
811 }
812 impl Vertical {
813 variant: Mark,
814 }
815 ),
816 (
817 struct Adjust<'a> {
818 content: Vec<Vertical<'a>>,
819 }
820 impl Func {
821 func_name: "adjust",
822 default_num_pos_arg: 0,
823 }
824 impl Horizontal {
825 variant: Adjust,
826 }
827 ),
828 (
829 struct Insertion<'a> {
830 box_number: i32,
831 height: common::Scaled,
832 split_max_depth: common::Scaled,
833 split_top_skip_width: common::Scaled,
834 split_top_skip_stretch: (common::Scaled, common::GlueOrder),
835 split_top_skip_shrink: (common::Scaled, common::GlueOrder),
836 float_penalty: i32,
837 vbox: Vec<Vertical<'a>>,
838 }
839 impl Func {
840 func_name: "insertion",
841 default_num_pos_arg: 1,
842 }
843 impl Horizontal {
844 variant: Insertion,
845 }
846 impl Vertical {
847 variant: Insertion,
848 }
849 ),
850 (
851 struct Math<'a> {
852 kind: Cow<'a, str>,
853 }
854 impl Func {
855 func_name: "math",
856 default_num_pos_arg: 1,
857 }
858 impl Horizontal {
859 variant: Math,
860 }
861 impl Vertical {
862 variant: Math,
863 }
864 ),
865);
866
867impl<'a> std::fmt::Display for VBox<'a> {
868 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
869 let v_box: VBox<'a> = self.clone();
870 let tree = CstTreeIter::Other(&Horizontal::VBox(v_box));
871 cst::pretty_print(f, tree)?;
872 Ok(())
873 }
874}
875
876impl<'a> std::fmt::Display for HBox<'a> {
877 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
878 let v_box: HBox<'a> = self.clone();
879 let tree = CstTreeIter::Other(&Horizontal::HBox(v_box));
880 cst::pretty_print(f, tree)?;
881 Ok(())
882 }
883}
884
885#[derive(Debug, Default, PartialEq, Eq, Clone)]
887pub struct Arg<'a, T> {
888 pub value: T,
890 pub source: Option<Str<'a>>,
895}
896
897impl<'a, T> From<T> for Arg<'a, T> {
898 fn from(value: T) -> Self {
899 Arg {
900 value,
901 source: None,
902 }
903 }
904}
905
906#[allow(private_bounds)]
910impl<'a, T> Arg<'a, T>
911where
912 T: Value<'a>,
913{
914 fn assign<F: cst::TreeIter<'a>>(
915 &mut self,
916 arg: cst::ArgsItem<'a, F>,
917 field_name: &'a str,
918 func_name: Str<'a>,
919 value_source: Str<'a>,
920 errs: &ErrorAccumulator<'a>,
921 ) {
922 if let Some(first_assignment) = &self.source {
923 errs.add(Error::DuplicateArgument {
924 parameter_name: field_name,
925 first_assignment: first_assignment.clone(),
926 second_assignment: value_source,
927 });
928 return;
929 }
930 let (cast_result, value_type) = match arg {
931 cst::ArgsItem::Regular { value, .. } => match &value {
932 cst::Value::List(tree) => (T::try_cast_list(tree.iter(), errs), "a list"),
933 cst::Value::Integer(i) => (T::try_cast_integer(*i), "an integer"),
934 cst::Value::Scaled(scaled) => (T::try_cast_scaled(*scaled), "a number"),
935 cst::Value::InfiniteGlue(scaled, glue_order) => (
936 T::try_cast_infinite_glue(*scaled, *glue_order),
937 "an infinite glue",
938 ),
939 cst::Value::String(cow) => (T::try_cast_string(cow.clone()), "a string"),
940 },
941 cst::ArgsItem::List { tree, .. } => (T::try_cast_list(tree, errs), "a list"),
942 cst::ArgsItem::Comment { .. } => return,
943 };
944 match cast_result {
945 Some(val) => {
946 self.value = val;
947 self.source = Some(value_source);
948 }
949 None => errs.add(Error::IncorrectType {
950 wanted_type: T::DESCRIPTION,
951 got_type: value_type,
952 got_raw_value: value_source,
953 function_name: func_name,
954 parameter_name: field_name,
955 }),
956 }
957 }
958}
959
960#[derive(Debug, PartialEq, Eq, Clone, Copy)]
965pub enum MaybeRunning {
966 Running,
967 Scaled(common::Scaled),
968}
969
970impl Default for MaybeRunning {
971 fn default() -> Self {
972 MaybeRunning::Scaled(common::Scaled::ZERO)
973 }
974}
975
976impl MaybeRunning {
977 pub fn to_scaled(self) -> common::Scaled {
978 match self {
979 MaybeRunning::Running => common::Scaled(i32::MIN),
980 MaybeRunning::Scaled(s) => s,
981 }
982 }
983
984 pub fn from_scaled(s: common::Scaled) -> Self {
985 if s.0 == i32::MIN {
986 MaybeRunning::Running
987 } else {
988 MaybeRunning::Scaled(s)
989 }
990 }
991}
992
993trait Value<'a>: Sized {
998 const DESCRIPTION: &'static str;
999
1000 fn try_cast_integer(_i: i32) -> Option<Self> {
1001 None
1002 }
1003 fn try_cast_string(_s: Cow<'a, str>) -> Option<Self> {
1004 None
1005 }
1006 fn try_cast_scaled(_s: common::Scaled) -> Option<Self> {
1007 None
1008 }
1009 fn try_cast_infinite_glue(_s: common::Scaled, _o: common::GlueOrder) -> Option<Self> {
1010 None
1011 }
1012 fn try_cast_list<F: cst::TreeIter<'a>>(
1013 _value: F,
1014 _errs: &ErrorAccumulator<'a>,
1015 ) -> Option<Self> {
1016 None
1017 }
1018
1019 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>>;
1020}
1021
1022impl<'a> Value<'a> for bool {
1023 const DESCRIPTION: &'static str = "a boolean (\"true\" or \"false\")";
1024 fn try_cast_string(s: Cow<'a, str>) -> Option<Self> {
1025 match s.as_ref() {
1026 "true" => Some(true),
1027 "false" => Some(false),
1028 _ => None,
1029 }
1030 }
1031 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1032 cst::ArgsItem::Regular {
1033 key,
1034 value: cst::Value::String(if *self { "true" } else { "false" }.into()),
1035 value_source: "".into(),
1036 }
1037 }
1038}
1039
1040impl<'a> Value<'a> for common::GlueOrder {
1041 const DESCRIPTION: &'static str = "a glue sign (normal, stretching or shrinking)";
1042 fn try_cast_string(s: Cow<'a, str>) -> Option<Self> {
1043 match s.as_ref() {
1044 "normal" => Some(Self::Normal),
1045 "fil" => Some(Self::Fil),
1046 "fill" => Some(Self::Fill),
1047 "filll" => Some(Self::Filll),
1048 _ => None,
1049 }
1050 }
1051 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1052 use common::GlueOrder::*;
1053 cst::ArgsItem::Regular {
1054 key,
1055 value: cst::Value::String(
1056 match self {
1057 Normal => "normal",
1058 Fil => "fil",
1059 Fill => "fill",
1060 Filll => "filll",
1061 }
1062 .into(),
1063 ),
1064 value_source: "".into(),
1065 }
1066 }
1067}
1068
1069impl<'a> Value<'a> for crate::ds::GlueRatio {
1070 const DESCRIPTION: &'static str = "a glue ratio (floating point number)";
1071 fn try_cast_string(s: Cow<'a, str>) -> Option<Self> {
1072 crate::ds::GlueRatio::from_float_str(&s)
1073 }
1074 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1075 cst::ArgsItem::Regular {
1076 key,
1077 value: cst::Value::String(format!["{}", self].into()),
1078 value_source: "".into(),
1079 }
1080 }
1081}
1082
1083impl<'a> Value<'a> for char {
1084 const DESCRIPTION: &'static str = "a character (i.e. a string containing single character)";
1085 fn try_cast_string(s: Cow<'a, str>) -> Option<Self> {
1086 let mut iter = s.chars();
1087 let c = iter.next()?;
1088 match iter.next() {
1089 Some(_) => None,
1090 None => Some(c),
1091 }
1092 }
1093 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1094 let s = format!("{self}");
1095 cst::ArgsItem::Regular {
1096 key,
1097 value: cst::Value::String(s.into()),
1098 value_source: "".into(),
1099 }
1100 }
1101}
1102
1103impl<'a> Value<'a> for Cow<'a, str> {
1104 const DESCRIPTION: &'static str = "a string";
1105 fn try_cast_string(s: Cow<'a, str>) -> Option<Self> {
1106 Some(s)
1107 }
1108 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1109 cst::ArgsItem::Regular {
1110 key,
1111 value: cst::Value::String(self.clone()),
1112 value_source: "".into(),
1113 }
1114 }
1115}
1116
1117impl<'a> Value<'a> for i32 {
1118 const DESCRIPTION: &'static str = "an integer";
1119 fn try_cast_integer(i: i32) -> Option<Self> {
1120 Some(i)
1121 }
1122 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1123 cst::ArgsItem::Regular {
1124 key,
1125 value: cst::Value::Integer(*self),
1126 value_source: "".into(),
1127 }
1128 }
1129}
1130
1131impl<'a> Value<'a> for common::FontId {
1132 const DESCRIPTION: &'static str = "a font ID (a non-negative integer)";
1133 fn try_cast_integer(i: i32) -> Option<Self> {
1134 Some(common::FontId(i as u32))
1135 }
1136 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1137 cst::ArgsItem::Regular {
1138 key,
1139 value: cst::Value::Integer(self.0 as i32),
1140 value_source: "".into(),
1141 }
1142 }
1143}
1144
1145impl<'a> Value<'a> for common::Scaled {
1146 const DESCRIPTION: &'static str = "a number";
1147 fn try_cast_scaled(s: common::Scaled) -> Option<Self> {
1148 Some(s)
1149 }
1150 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1151 cst::ArgsItem::Regular {
1152 key,
1153 value: cst::Value::Scaled(*self),
1154 value_source: "".into(),
1155 }
1156 }
1157}
1158
1159impl<'a> Value<'a> for MaybeRunning {
1160 const DESCRIPTION: &'static str = "a dimension or *";
1161 fn try_cast_scaled(s: common::Scaled) -> Option<Self> {
1162 Some(MaybeRunning::Scaled(s))
1163 }
1164 fn try_cast_string(s: Cow<'a, str>) -> Option<Self> {
1165 if s == "running" {
1166 Some(MaybeRunning::Running)
1167 } else {
1168 None
1169 }
1170 }
1171 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1172 let value = match self {
1173 MaybeRunning::Running => cst::Value::String("running".into()),
1174 MaybeRunning::Scaled(s) => cst::Value::Scaled(*s),
1175 };
1176 cst::ArgsItem::Regular {
1177 key,
1178 value,
1179 value_source: "".into(),
1180 }
1181 }
1182}
1183
1184impl<'a> Value<'a> for (common::Scaled, common::GlueOrder) {
1185 const DESCRIPTION: &'static str = "a stretch or shrink glue component";
1186 fn try_cast_scaled(s: common::Scaled) -> Option<Self> {
1187 Some((s, common::GlueOrder::Normal))
1188 }
1189 fn try_cast_infinite_glue(s: common::Scaled, o: common::GlueOrder) -> Option<Self> {
1190 Some((s, o))
1191 }
1192 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1193 cst::ArgsItem::Regular {
1194 key,
1195 value: cst::Value::InfiniteGlue(self.0, self.1),
1196 value_source: "".into(),
1197 }
1198 }
1199}
1200
1201impl<'a> Value<'a> for Vec<Vertical<'a>> {
1202 const DESCRIPTION: &'static str = "a vbox";
1203 fn try_cast_list<F: cst::TreeIter<'a>>(value: F, errs: &ErrorAccumulator<'a>) -> Option<Self> {
1204 Some(parse_vbox_using_cst(value, errs))
1205 }
1206 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1207 cst::ArgsItem::List {
1208 key,
1209 square_open: "".into(),
1210 tree: lower_vbox_impl(self),
1211 }
1212 }
1213}
1214
1215impl<'a> Value<'a> for Vec<Horizontal<'a>> {
1216 const DESCRIPTION: &'static str = "a hbox";
1217 fn try_cast_list<F: cst::TreeIter<'a>>(value: F, errs: &ErrorAccumulator<'a>) -> Option<Self> {
1218 Some(parse_hbox_using_cst(value, errs))
1219 }
1220 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1221 cst::ArgsItem::List {
1222 key,
1223 square_open: "".into(),
1224 tree: lower_hbox_impl(self),
1225 }
1226 }
1227}
1228
1229impl<'a> Value<'a> for Vec<DiscretionaryElem<'a>> {
1230 const DESCRIPTION: &'static str = "a dlist";
1231 fn try_cast_list<F: cst::TreeIter<'a>>(value: F, errs: &ErrorAccumulator<'a>) -> Option<Self> {
1232 Some(parse_dlist_using_cst(value, errs))
1233 }
1234 fn lower<'b>(&'b self, key: Option<Str<'a>>) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1235 cst::ArgsItem::List {
1236 key,
1237 square_open: "".into(),
1238 tree: lower_dlist_impl(self),
1239 }
1240 }
1241}
1242
1243fn value_to_cst<'a, 'b, V: Value<'a>>(
1244 value: &'b V,
1245 key: Option<Str<'a>>,
1246) -> cst::ArgsItem<'a, CstTreeIter<'a, 'b>> {
1247 value.lower(key)
1250}
1251
1252#[cfg(test)]
1253mod tests {
1254 use super::*;
1255 #[test]
1257 fn hbox() {
1258 let input = r#"
1259 hbox(
1260 width=1pt,
1261 content=[chars("Hello")],
1262 )
1263 "#;
1264
1265 let want = vec![Horizontal::HBox(HBox {
1266 width: Arg {
1267 value: common::Scaled::ONE.into(),
1268 source: Some("1pt".into()),
1269 },
1270 content: Arg {
1271 value: vec![Horizontal::Chars(Chars {
1272 content: Arg {
1273 value: "Hello".into(),
1274 source: Some(r#""Hello""#.into()),
1275 },
1276 font: Arg {
1277 value: common::FontId::ONE,
1278 source: None,
1279 },
1280 ..Default::default()
1281 })],
1282 source: Some(r#"[chars("Hello")]"#.into()),
1283 },
1284 ..Default::default()
1285 })];
1286
1287 let got = parse_hbox(&input).expect("parsing succeeds");
1288
1289 assert_eq!(got, want);
1290 }
1291}