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