1use super::cst;
6use super::error::*;
7use crate::{ligkern::lang::PostLigOperation, Char, Face, FixWord, NamedParameter};
8use std::ops::Range;
9
10#[derive(Debug, PartialEq, Eq)]
14#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
15pub struct Ast(pub Vec<Root>);
16
17impl Ast {
18 pub fn from_pl_source_code(source: &str) -> (Ast, Vec<ParseWarning>) {
20 let (cst, mut errors) = cst::Cst::from_pl_source_code(source);
21 let ast = Ast::from_cst(cst, &mut errors);
22 (Ast(ast), errors)
23 }
24
25 pub fn from_cst(cst: cst::Cst, errors: &mut Vec<ParseWarning>) -> Vec<Root> {
27 cst.0
28 .into_iter()
29 .filter_map(|c| Root::build(c, errors))
30 .collect()
31 }
32 pub fn lower(self, char_display_format: super::CharDisplayFormat) -> cst::Cst {
34 cst::Cst(
35 self.0
36 .into_iter()
37 .map(|c| Root::lower(c, char_display_format))
38 .collect(),
39 )
40 }
41}
42
43#[derive(PartialEq, Eq, Debug)]
47pub struct SingleValue<D> {
48 pub data: D,
50 pub data_span: Range<usize>,
52 }
54
55impl<D> From<D> for SingleValue<D> {
56 fn from(data: D) -> Self {
57 Self {
58 data,
59 data_span: 0..0,
60 }
61 }
62}
63
64#[cfg(feature = "arbitrary")]
65impl<'a, D> arbitrary::Arbitrary<'a> for SingleValue<D>
66where
67 D: arbitrary::Arbitrary<'a>,
68{
69 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
70 Ok(D::arbitrary(u)?.into())
71 }
72}
73
74#[derive(PartialEq, Eq, Debug, Clone)]
79pub struct TupleValue<D, E> {
80 pub left: D,
82 pub left_span: Range<usize>,
84 pub right: E,
86 pub right_span: Range<usize>,
88}
89
90impl<D, E> From<(D, E)> for TupleValue<D, E> {
91 fn from(value: (D, E)) -> Self {
92 Self {
93 left: value.0,
94 left_span: 0..0,
95 right: value.1,
96 right_span: 0..0,
97 }
98 }
99}
100
101#[cfg(feature = "arbitrary")]
102impl<'a, D, E> arbitrary::Arbitrary<'a> for TupleValue<D, E>
103where
104 D: arbitrary::Arbitrary<'a>,
105 E: arbitrary::Arbitrary<'a>,
106{
107 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
108 Ok(<(D, E)>::arbitrary(u)?.into())
109 }
110}
111
112#[derive(PartialEq, Eq, Debug)]
118pub struct Branch<D, E> {
119 pub data: D,
121 pub data_span: Range<usize>,
123 pub children: Vec<E>,
126}
127
128impl<D, E> From<(D, Vec<E>)> for Branch<D, E> {
129 fn from(value: (D, Vec<E>)) -> Self {
130 Self {
131 data: value.0,
132 data_span: 0..0,
133 children: value.1,
134 }
135 }
136}
137
138#[cfg(feature = "arbitrary")]
139impl<'a, D, E> arbitrary::Arbitrary<'a> for Branch<D, E>
140where
141 D: arbitrary::Arbitrary<'a>,
142 E: arbitrary::Arbitrary<'a>,
143{
144 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
145 Ok(<(D, Vec<E>)>::arbitrary(u)?.into())
146 }
147}
148
149trait ToFromCstNode: Sized {
160 fn from_cst_node(p: cst::RegularNode, errors: &mut Vec<ParseWarning>) -> Option<Self>;
161 fn to_cst_node(self, key: &'static str, opts: &LowerOpts) -> cst::RegularNode;
162}
163
164struct LowerOpts {
165 char_display_format: super::CharDisplayFormat,
166}
167
168impl<D: TryParse> ToFromCstNode for SingleValue<D> {
169 fn from_cst_node(p: cst::RegularNode, errors: &mut Vec<ParseWarning>) -> Option<Self> {
170 let (mut input, _) = Input::new(p, errors);
171 let result = D::try_parse(&mut input).map(|data| Self {
172 data: data.0,
173 data_span: data.1,
174 });
175 input.find_junk(false);
176 result
177 }
178 fn to_cst_node(self, key: &'static str, opts: &LowerOpts) -> cst::RegularNode {
179 cst::RegularNode {
180 opening_parenthesis_span: 0..0,
181 key: key.into(),
182 key_span: 0..0,
183 data: TryParse::to_string(self.data, opts),
184 data_span: self.data_span,
185 children: None,
186 closing_parenthesis_span: 0..0,
187 }
188 }
189}
190
191impl<D: TryParse, E: Parse> ToFromCstNode for TupleValue<D, E> {
192 fn from_cst_node(p: cst::RegularNode, errors: &mut Vec<ParseWarning>) -> Option<Self> {
193 let (mut input, _) = Input::new(p, errors);
194 let (left, left_span) = D::try_parse(&mut input)?;
195 let (right, right_span) = E::parse(&mut input);
196 input.find_junk(false);
197 Some(Self {
198 left,
199 left_span,
200 right,
201 right_span,
202 })
203 }
204 fn to_cst_node(self, key: &'static str, opts: &LowerOpts) -> cst::RegularNode {
205 cst::RegularNode {
206 opening_parenthesis_span: 0..0,
207 key: key.into(),
208 key_span: 0..0,
209 data: Some(format![
210 "{} {}",
211 TryParse::to_string(self.left, opts).expect("In TupleValue<D, E>, D != ()"),
212 Parse::to_string(self.right, opts).expect("In TupleValue<D, E>, E != ()")
213 ]),
214 data_span: self.left_span.start..self.right_span.end,
215 children: None,
216 closing_parenthesis_span: 0..0,
217 }
218 }
219}
220
221impl<D: Parse, E: Node> ToFromCstNode for Branch<D, E> {
222 fn from_cst_node(p: cst::RegularNode, errors: &mut Vec<ParseWarning>) -> Option<Self> {
223 {
224 let (mut input, children) = Input::new(p, errors);
225 let (data, data_span) = D::parse(&mut input);
226 input.find_junk(true);
227 Some(Branch::<D, E> {
228 data,
229 data_span,
230 children: children
231 .into_iter()
232 .filter_map(|c| Node::build(c, errors))
233 .collect(),
234 })
235 }
236 }
237 fn to_cst_node(self, key: &'static str, opts: &LowerOpts) -> cst::RegularNode {
238 cst::RegularNode {
239 opening_parenthesis_span: 0..0,
240 key: key.into(),
241 key_span: 0..0,
242 data: TryParse::to_string(self.data, opts),
243 data_span: self.data_span,
244 children: Some(
245 self.children
246 .into_iter()
247 .map(|c| E::lower(c, opts))
248 .collect(),
249 ),
250 closing_parenthesis_span: 0..0,
251 }
252 }
253}
254
255trait Node: Sized {
256 fn build_regular(p: cst::RegularNode, errors: &mut Vec<ParseWarning>) -> Option<Self>;
257 fn build_comment(s: String) -> Self;
258 fn build(n: cst::Node, errors: &mut Vec<ParseWarning>) -> Option<Self> {
259 match n {
260 cst::Node::Comment(c) => Some(Node::build_comment(c)),
261 cst::Node::Regular(r) => Node::build_regular(r, errors),
262 }
263 }
264 fn lower(self, opts: &LowerOpts) -> cst::Node;
265}
266
267macro_rules! node_impl {
268 ( $type: ident, $( ($key: ident, $str: expr, $variant: ident $(, $prefix: path )? ), )+ ) => {
269
270 impl $type {
271 $(
272 pub const $key: &'static str = $str;
273 )+
274
275 pub const ALL_PROPERTY_NAMES: &'static [&'static str] = &[$( $str, )+];
276 }
277
278 impl Node for $type {
279 fn build_regular(mut r: cst::RegularNode, errors: &mut Vec<ParseWarning>) -> Option<Self> {
280 r.key.make_ascii_uppercase();
281 match r.key.as_str() {
282 $(
283 $type::$key => {
284 match ToFromCstNode::from_cst_node(r, errors) {
285 None => None,
286 Some(v) => Some($type::$variant( $( $prefix, )? v )),
287 }
288 },
289 )+
290 _ => {
291 errors.push(ParseWarning{
292 span: r.key_span.clone(),
293 knuth_pltotf_offset: Some(r.key_span.end),
294 kind: ParseWarningKind::InvalidPropertyName {
295 provided_name: r.key.into(),
296 allowed_property_names: $type::ALL_PROPERTY_NAMES,
297 }
298 });
299 None
300 },
301 }
302 }
303 fn build_comment(s: String) -> Self {
304 $type::Comment(s)
305 }
306 fn lower(self, opts: &LowerOpts) -> cst::Node {
307 match self {
308 $(
309 $type::$variant($( $prefix, )? v) => {
310 cst::Node::Regular(v.to_cst_node($str, opts))
311 }
312 )+
313 $type::Comment(balanced_elements) => {
314 cst::Node::Comment(balanced_elements)
315 }
316 }
317 }
318 }
319 impl $type {
320 pub fn lower(self, char_display_format: super::CharDisplayFormat) -> cst::Node {
321 let opts = LowerOpts {
322 char_display_format,
323 };
324 Node::lower(self, &opts)
325 }
326 }
327 };
328}
329
330#[derive(PartialEq, Eq, Debug)]
334#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
335pub enum Root {
336 Checksum(SingleValue<u32>),
342
343 DesignSize(SingleValue<DesignSize>),
351
352 DesignUnits(SingleValue<FixWord>),
359
360 CodingScheme(SingleValue<String>),
364
365 Family(SingleValue<String>),
370
371 Face(SingleValue<Face>),
377
378 SevenBitSafeFlag(SingleValue<bool>),
385
386 Header(TupleValue<DecimalU8, u32>),
393
394 FontDimension(Branch<(), FontDimension>),
396
397 LigTable(Branch<(), LigTable>),
399
400 BoundaryChar(SingleValue<Char>),
405
406 Character(Branch<Char, Character>),
410
411 Comment(String),
413}
414
415node_impl!(
416 Root,
417 (CHECKSUM, "CHECKSUM", Checksum),
418 (DESIGN_SIZE, "DESIGNSIZE", DesignSize),
419 (DESIGN_UNITS, "DESIGNUNITS", DesignUnits),
420 (CODING_SCHEME, "CODINGSCHEME", CodingScheme),
421 (FAMILY, "FAMILY", Family),
422 (FACE, "FACE", Face),
423 (SEVEN_BIT_SAFE_FLAG, "SEVENBITSAFEFLAG", SevenBitSafeFlag),
424 (HEADER, "HEADER", Header),
425 (FONT_DIMENSION, "FONTDIMEN", FontDimension),
426 (LIG_TABLE, "LIGTABLE", LigTable),
427 (BOUNDARY_CHAR, "BOUNDARYCHAR", BoundaryChar),
428 (CHARACTER, "CHARACTER", Character),
429);
430
431#[derive(PartialEq, Eq, Debug)]
439#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
440pub enum FontDimension {
441 NamedParam(NamedParameter, SingleValue<FixWord>),
443
444 IndexedParam(TupleValue<ParameterNumber, FixWord>),
448
449 Comment(String),
451}
452
453#[derive(Debug, PartialEq, Eq)]
455#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
456pub struct DecimalU8(pub u8);
457
458impl Parse for DecimalU8 {
459 fn parse(input: &mut Input) -> (Self, Range<usize>) {
460 let (a, b) = u8::parse(input);
461 (DecimalU8(a), b)
462 }
463
464 fn to_string(self, _: &LowerOpts) -> Option<String> {
465 Some(format!["D {}", self.0])
466 }
467}
468
469#[derive(PartialEq, Eq, Debug)]
470#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
471pub struct ParameterNumber(pub u16);
472
473impl TryParse for ParameterNumber {
474 fn try_parse(input: &mut Input) -> Option<(Self, Range<usize>)> {
475 input.consume_spaces();
476 let span_start = input.raw_data_span.start;
477 let (a, err_or) = match parse_u8(input) {
478 Ok(u) => (u, None),
479 Err(err) => {
480 input.skip_error(err.clone().into());
481 (0, Some(err))
482 }
483 };
484 let b = span_start..input.raw_data_span.start;
485 match a {
486 0 => {
487 input.skip_error(ParseWarning {
488 span: b.clone(),
489 knuth_pltotf_offset: Some(match err_or {
490 Some(ParseU8Error::SmallIntegerIsTooBig { .. }) => b.end - 1,
493 _ => b.end,
494 }),
495 kind: ParseWarningKind::ParameterNumberIsZero,
496 });
497 None
498 }
499 u8::MAX => {
500 input.skip_error(ParseWarning {
501 span: b.clone(),
502 knuth_pltotf_offset: Some(b.end),
503 kind: ParseWarningKind::ParameterNumberIsTooBig,
504 });
505 None
506 }
507 n => Some((ParameterNumber(n as u16), b)),
508 }
509 }
510
511 fn to_string(self, _: &LowerOpts) -> Option<String> {
512 Some(format!["D {}", self.0])
513 }
514}
515
516node_impl!(
517 FontDimension,
518 (SLANT, "SLANT", NamedParam, NamedParameter::Slant),
519 (SPACE, "SPACE", NamedParam, NamedParameter::Space),
520 (STRETCH, "STRETCH", NamedParam, NamedParameter::Stretch),
521 (SHRINK, "SHRINK", NamedParam, NamedParameter::Shrink),
522 (X_HEIGHT, "XHEIGHT", NamedParam, NamedParameter::XHeight),
523 (QUAD, "QUAD", NamedParam, NamedParameter::Quad),
524 (
525 EXTRA_SPACE,
526 "EXTRASPACE",
527 NamedParam,
528 NamedParameter::ExtraSpace
529 ),
530 (NUM_1, "NUM1", NamedParam, NamedParameter::Num1),
531 (NUM_2, "NUM2", NamedParam, NamedParameter::Num2),
532 (NUM_3, "NUM3", NamedParam, NamedParameter::Num3),
533 (DENOM_1, "DENOM1", NamedParam, NamedParameter::Denom1),
534 (DENOM_2, "DENOM2", NamedParam, NamedParameter::Denom2),
535 (SUP_1, "SUP1", NamedParam, NamedParameter::Sup1),
536 (SUP_2, "SUP2", NamedParam, NamedParameter::Sup2),
537 (SUP_3, "SUP3", NamedParam, NamedParameter::Sup3),
538 (SUB_1, "SUB1", NamedParam, NamedParameter::Sub1),
539 (SUB_2, "SUB2", NamedParam, NamedParameter::Sub2),
540 (SUP_DROP, "SUPDROP", NamedParam, NamedParameter::SupDrop),
541 (SUB_DROP, "SUBDROP", NamedParam, NamedParameter::SubDrop),
542 (DELIM_1, "DELIM1", NamedParam, NamedParameter::Delim1),
543 (DELIM_2, "DELIM2", NamedParam, NamedParameter::Delim2),
544 (
545 AXIS_HEIGHT,
546 "AXISHEIGHT",
547 NamedParam,
548 NamedParameter::AxisHeight
549 ),
550 (
551 DEFAULT_RULE_THICKNESS,
552 "DEFAULTRULETHICKNESS",
553 NamedParam,
554 NamedParameter::DefaultRuleThickness
555 ),
556 (
557 BIG_OP_SPACING_1,
558 "BIGOPSPACING1",
559 NamedParam,
560 NamedParameter::BigOpSpacing1
561 ),
562 (
563 BIG_OP_SPACING_2,
564 "BIGOPSPACING2",
565 NamedParam,
566 NamedParameter::BigOpSpacing2
567 ),
568 (
569 BIG_OP_SPACING_3,
570 "BIGOPSPACING3",
571 NamedParam,
572 NamedParameter::BigOpSpacing3
573 ),
574 (
575 BIG_OP_SPACING_4,
576 "BIGOPSPACING4",
577 NamedParam,
578 NamedParameter::BigOpSpacing4
579 ),
580 (
581 BIG_OP_SPACING_5,
582 "BIGOPSPACING5",
583 NamedParam,
584 NamedParameter::BigOpSpacing5
585 ),
586 (PARAMETER, "PARAMETER", IndexedParam),
587);
588
589#[derive(PartialEq, Eq, Debug)]
593#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
594pub enum Character {
595 Width(SingleValue<Option<FixWord>>),
597
598 Height(SingleValue<FixWord>),
600
601 Depth(SingleValue<FixWord>),
603
604 ItalicCorrection(SingleValue<FixWord>),
606
607 NextLarger(SingleValue<Char>),
611
612 ExtensibleCharacter(Branch<(), ExtensibleCharacter>),
616
617 Comment(String),
619}
620
621node_impl!(
622 Character,
623 (WIDTH, "CHARWD", Width),
624 (HEIGHT, "CHARHT", Height),
625 (DEPTH, "CHARDP", Depth),
626 (ITALIC_CORRECTION, "CHARIC", ItalicCorrection),
627 (NEXT_LARGER, "NEXTLARGER", NextLarger),
628 (EXTENSIBLE_CHARACTER, "VARCHAR", ExtensibleCharacter),
629);
630
631#[derive(PartialEq, Eq, Debug)]
635#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
636pub enum ExtensibleCharacter {
637 Top(SingleValue<Char>),
639
640 Middle(SingleValue<Char>),
642
643 Bottom(SingleValue<Char>),
645
646 Replicated(SingleValue<Char>),
648
649 Comment(String),
651}
652
653node_impl!(
654 ExtensibleCharacter,
655 (TOP, "TOP", Top),
656 (MIDDLE, "MID", Middle),
657 (BOTTOM, "BOT", Bottom),
658 (REPLICATED, "REP", Replicated),
659);
660
661#[derive(PartialEq, Eq, Debug)]
669#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
670pub enum LigTable {
671 Label(SingleValue<LigTableLabel>),
678
679 Lig(PostLigOperation, TupleValue<Char, Char>),
703
704 Kern(TupleValue<Char, FixWord>),
710
711 Stop(SingleValue<()>),
714
715 Skip(SingleValue<DecimalU8>),
719
720 Comment(String),
722}
723
724#[derive(PartialEq, Eq, Debug)]
726#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
727pub enum LigTableLabel {
728 Char(Char),
730 BoundaryChar,
732}
733
734impl Parse for LigTableLabel {
735 fn parse(input: &mut Input) -> (Self, Range<usize>) {
736 match input.peek() {
737 Some('B' | 'b') => {
738 let span_start = input.raw_data_offset;
739 input.skip_to_end();
740 (LigTableLabel::BoundaryChar, span_start..span_start + 1)
741 }
742 _ => {
743 let (c, span) = Parse::parse(input);
744 (LigTableLabel::Char(c), span)
745 }
746 }
747 }
748 fn to_string(self, opts: &LowerOpts) -> Option<String> {
749 match self {
750 LigTableLabel::Char(c) => Parse::to_string(c, opts),
751 LigTableLabel::BoundaryChar => Some("BOUNDARYCHAR".into()),
752 }
753 }
754}
755
756node_impl!(
757 LigTable,
758 (LABEL, "LABEL", Label),
759 (
760 LIG_1,
761 "LIG",
762 Lig,
763 PostLigOperation::RetainNeitherMoveToInserted
764 ),
765 (LIG_2, "/LIG", Lig, PostLigOperation::RetainLeftMoveNowhere),
766 (
767 LIG_3,
768 "/LIG>",
769 Lig,
770 PostLigOperation::RetainLeftMoveToInserted
771 ),
772 (
773 LIG_4,
774 "LIG/",
775 Lig,
776 PostLigOperation::RetainRightMoveToInserted
777 ),
778 (
779 LIG_5,
780 "LIG/>",
781 Lig,
782 PostLigOperation::RetainRightMoveToRight
783 ),
784 (LIG_6, "/LIG/", Lig, PostLigOperation::RetainBothMoveNowhere),
785 (
786 LIG_7,
787 "/LIG/>",
788 Lig,
789 PostLigOperation::RetainBothMoveToInserted
790 ),
791 (
792 LIG_8,
793 "/LIG/>>",
794 Lig,
795 PostLigOperation::RetainBothMoveToRight
796 ),
797 (KERN, "KRN", Kern),
798 (STOP, "STOP", Stop),
799 (SKIP, "SKIP", Skip),
800);
801
802trait Parse: Sized {
803 fn parse(input: &mut Input) -> (Self, Range<usize>);
804 fn to_string(self, opts: &LowerOpts) -> Option<String>;
805}
806
807trait TryParse: Sized {
808 fn try_parse(input: &mut Input) -> Option<(Self, Range<usize>)>;
809 fn to_string(self, opts: &LowerOpts) -> Option<String>;
810}
811
812impl<T: Parse> TryParse for T {
813 fn try_parse(input: &mut Input) -> Option<(Self, Range<usize>)> {
814 Some(Parse::parse(input))
815 }
816 fn to_string(self, opts: &LowerOpts) -> Option<String> {
817 Parse::to_string(self, opts)
818 }
819}
820
821#[derive(Debug)]
822struct Input<'a> {
823 raw_data: String,
824 raw_data_offset: usize,
825 raw_data_span: Range<usize>,
826 errors: &'a mut Vec<ParseWarning>,
827}
828
829impl<'a> Input<'a> {
830 fn new(p: cst::RegularNode, errors: &'a mut Vec<ParseWarning>) -> (Self, Vec<cst::Node>) {
831 (
832 Input {
833 raw_data: p.data.unwrap_or_default(),
834 raw_data_offset: 0,
835 errors,
836 raw_data_span: p.data_span,
837 },
838 p.children.unwrap_or_default(),
839 )
840 }
841 fn skip_error(&mut self, error: ParseWarning) {
842 self.errors.push(error);
843 self.skip_to_end();
844 }
845 fn skip_to_end(&mut self) {
846 while self.next().is_some() {}
847 }
848 fn peek(&self) -> Option<char> {
849 self.raw_data[self.raw_data_offset..].chars().next()
850 }
851 fn consume_spaces(&mut self) {
852 while self.raw_data[self.raw_data_offset..].starts_with([' ', '\n']) {
853 self.raw_data_offset += 1;
854 self.raw_data_span.start += 1;
855 }
856 }
857 fn last_span(&self, last: Option<char>) -> Range<usize> {
858 let end_span = self.raw_data_span.start;
859 match last {
860 None => end_span..end_span,
861 Some(_) => end_span - 1..end_span,
862 }
863 }
864 fn take_string(&mut self) -> String {
865 assert_eq!(self.raw_data_offset, 0);
866 let mut res = String::new();
867 std::mem::swap(&mut res, &mut self.raw_data);
868 self.raw_data_span.start = self.raw_data_span.end;
869 res
870 }
871 fn find_junk(&mut self, is_branch: bool) {
872 self.consume_spaces();
873 if !self.raw_data_span.is_empty() {
874 let span = self.raw_data_span.clone();
875 let knuth_pltotf_offset = Some(self.raw_data_span.start + 1);
876 let junk: String = self.collect();
877 self.errors.push(ParseWarning {
878 span,
879 knuth_pltotf_offset,
880 kind: if is_branch {
881 ParseWarningKind::JunkInsidePropertyList { junk }
882 } else {
883 ParseWarningKind::JunkAfterPropertyValue { junk }
884 },
885 })
886 }
887 }
888}
889
890impl<'a> Iterator for Input<'a> {
891 type Item = char;
892 fn next(&mut self) -> Option<Self::Item> {
893 let res = self.raw_data[self.raw_data_offset..].chars().next();
894 if let Some(c) = res {
895 if !c.is_ascii_graphic() && c != ' ' {
896 self.errors.push(ParseWarning {
897 span: self.raw_data_span.start..self.raw_data_span.start + 1,
898 knuth_pltotf_offset: Some(self.raw_data_span.start + 1),
899 kind: ParseWarningKind::NonVisibleAsciiCharacter { character: c },
900 });
901 }
902 self.raw_data_offset += c.len_utf8();
903 self.raw_data_span.start += 1;
904 }
905 res
906 }
907}
908
909impl Parse for () {
910 fn parse(input: &mut Input) -> (Self, Range<usize>) {
911 ((), input.raw_data_span.start..input.raw_data_span.start)
912 }
913 fn to_string(self, _: &LowerOpts) -> Option<String> {
914 None
915 }
916}
917
918impl Parse for u32 {
919 fn parse(input: &mut Input) -> (Self, Range<usize>) {
921 input.consume_spaces();
922 let start_span = input.raw_data_span.start;
923 let radix = match input.next() {
924 Some('O' | 'o') => 8_u8,
925 Some('H' | 'h') => 16,
926 c => {
927 let span = input.last_span(c);
928 input.skip_error(ParseWarning {
929 span: span.clone(),
930 knuth_pltotf_offset: Some(span.end),
931 kind: ParseWarningKind::InvalidPrefixForInteger { prefix: c },
932 });
933 return (0, span);
934 }
935 };
936 input.consume_spaces();
937 let number_start_span = input.raw_data_span.start;
938 let mut acc: u32 = 0;
939 while let Some(c) = input.peek() {
940 let n: u32 = match c.to_digit(16) {
941 None => break,
942 Some(d) => d,
943 };
944 input.next();
945 if n >= radix as u32 {
946 let span_start = input.raw_data_span.start - 1;
947 input.skip_error(ParseWarning {
948 span: span_start..span_start + 1,
949 knuth_pltotf_offset: Some(span_start + 1),
950 kind: ParseWarningKind::InvalidOctalDigit { invalid_digit: c },
951 });
952 break;
953 }
954 match acc
955 .checked_mul(radix as u32)
956 .and_then(|acc| acc.checked_add(n))
957 {
958 None => {
959 let knuth_pltotf_offset = input.raw_data_span.start;
963 while let Some(c) = input.peek() {
964 match c.to_digit(radix as u32) {
965 None => break,
966 Some(_) => input.next(),
967 };
968 }
969 let end_span = input.raw_data_span.start;
970 input.skip_error(ParseWarning {
971 span: number_start_span..end_span,
972 knuth_pltotf_offset: Some(knuth_pltotf_offset),
973 kind: ParseWarningKind::IntegerIsTooBig { radix },
974 });
975 break;
976 }
977 Some(new_acc) => acc = new_acc,
978 }
979 }
980 (acc, start_span..input.raw_data_span.start)
981 }
982 fn to_string(self, _: &LowerOpts) -> Option<String> {
983 Some(format!("O {self:o}"))
984 }
985}
986
987impl Parse for u8 {
988 fn parse(input: &mut Input) -> (Self, Range<usize>) {
989 input.consume_spaces();
990 let span_start = input.raw_data_span.start;
991 let u = match parse_u8(input) {
992 Ok(u) => u,
993 Err(err) => {
994 input.skip_error(err.into());
995 0
996 }
997 };
998 let span_end = input.raw_data_span.start;
999 (u, span_start..span_end)
1000 }
1001 fn to_string(self, _: &LowerOpts) -> Option<String> {
1002 Some(format!["O {self:o}"])
1003 }
1004}
1005
1006impl Parse for Char {
1007 fn parse(input: &mut Input) -> (Self, Range<usize>) {
1008 let (u, span) = u8::parse(input);
1009 (Char(u), span)
1010 }
1011 fn to_string(self, opts: &LowerOpts) -> Option<String> {
1012 use super::CharDisplayFormat;
1016 let output_as_ascii = match (opts.char_display_format, self.0 as char) {
1017 (CharDisplayFormat::Default, 'a'..='z' | 'A'..='Z' | '0'..='9') => true,
1018 (CharDisplayFormat::Ascii, '(' | ')') => false,
1019 (CharDisplayFormat::Ascii, '!'..='~') => true,
1020 _ => false,
1021 };
1022 if output_as_ascii {
1023 Some(format!("C {}", self.0 as char))
1024 } else {
1025 Parse::to_string(self.0, opts)
1026 }
1027 }
1028}
1029
1030impl Parse for String {
1031 fn parse(input: &mut Input) -> (Self, Range<usize>) {
1032 let span_start = input.raw_data_span.start;
1033 let s = input.take_string();
1034 let l = s.len();
1035 (s, span_start..span_start + l)
1036 }
1037 fn to_string(self, _: &LowerOpts) -> Option<String> {
1038 Some(self)
1039 }
1040}
1041
1042impl Parse for Face {
1043 fn parse(input: &mut Input) -> (Self, Range<usize>) {
1044 let (u, span) = u8::parse(input);
1045 (u.into(), span)
1046 }
1047 fn to_string(self, opts: &LowerOpts) -> Option<String> {
1048 match self {
1050 Face::Valid(w, s, e) => Some(format!(
1051 "F {}{}{}",
1052 match w {
1053 crate::FaceWeight::Light => 'L',
1054 crate::FaceWeight::Medium => 'M',
1055 crate::FaceWeight::Bold => 'B',
1056 },
1057 match s {
1058 crate::FaceSlope::Roman => 'R',
1059 crate::FaceSlope::Italic => 'I',
1060 },
1061 match e {
1062 crate::FaceExpansion::Regular => 'R',
1063 crate::FaceExpansion::Condensed => 'C',
1064 crate::FaceExpansion::Extended => 'E',
1065 },
1066 )),
1067 Face::Other(u) => Parse::to_string(u, opts),
1068 }
1069 }
1070}
1071
1072impl TryParse for bool {
1073 fn try_parse(input: &mut Input) -> Option<(Self, Range<usize>)> {
1074 let span_start = input.raw_data_span.start;
1076 let b = match input.next() {
1077 Some('T' | 't') => true,
1078 Some('F' | 'f') => false,
1079 _ => {
1080 input.skip_to_end();
1081 let span_end = input.raw_data_span.start;
1082 input.skip_error(ParseWarning {
1083 span: span_start..span_end,
1084 knuth_pltotf_offset: Some(span_start + 1),
1085 kind: ParseWarningKind::InvalidBoolean,
1086 });
1087 return None;
1088 }
1089 };
1090 let span_end = input.raw_data_span.start;
1091 input.skip_to_end();
1092 Some((b, span_start..span_end))
1093 }
1094 fn to_string(self, _: &LowerOpts) -> Option<String> {
1095 Some(if self { "TRUE" } else { "FALSE" }.into())
1096 }
1097}
1098
1099impl Parse for FixWord {
1100 fn parse(input: &mut Input) -> (Self, Range<usize>) {
1102 input.consume_spaces();
1103 let span_start = input.raw_data_span.start;
1104 match input.next() {
1105 Some('D' | 'd') | Some('R' | 'r') => (),
1106 c => {
1107 let span = input.last_span(c);
1108 input.skip_error(ParseWarning {
1109 span: span.clone(),
1110 knuth_pltotf_offset: Some(span.end),
1111 kind: ParseWarningKind::InvalidPrefixForDecimalNumber,
1112 });
1113 return (FixWord::ZERO, span);
1114 }
1115 }
1116 input.consume_spaces();
1117 let number_span_start = input.raw_data_span.start;
1118
1119 let negative = {
1121 let mut negative = false;
1122 loop {
1123 match input.peek() {
1124 Some('+' | ' ') => (),
1125 Some('-') => {
1126 negative = !negative;
1127 }
1128 _ => break,
1129 };
1130 input.next();
1131 }
1132 negative
1133 };
1134
1135 let integer_part = {
1136 let mut acc = 0_i32;
1137 while let Some(d) = input.peek().and_then(|c| c.to_digit(10)) {
1138 input.next();
1139 acc = acc.checked_mul(10).unwrap().checked_add(d as i32).unwrap();
1142 if acc >= 2048 {
1143 acc = 2048;
1146 }
1147 }
1148 acc
1149 };
1150
1151 let fractional_part = {
1152 let mut acc = 0_i32;
1153 if input.peek() == Some('.') {
1154 input.next();
1155 let mut fractional_digits = [0_i32; 7];
1157 for slot in &mut fractional_digits {
1158 match input.peek().and_then(|c| c.to_digit(10)) {
1159 Some(d) => {
1160 input.next();
1161 *slot = 0o10000000_i32.checked_mul(d as i32).unwrap();
1162 }
1163 None => break,
1164 }
1165 }
1166 for j in (0..7).rev() {
1167 acc = fractional_digits[j].checked_add(acc / 10).unwrap();
1168 }
1169 acc = (acc + 10) / 20;
1170 }
1171 acc
1172 };
1173
1174 if integer_part >= 2048 || (fractional_part >= FixWord::ONE.0 && integer_part == 2047) {
1175 let span_end = input.raw_data_span.start;
1176 input.skip_error(ParseWarning {
1177 span: number_span_start..span_end,
1178 knuth_pltotf_offset: Some(number_span_start),
1179 kind: ParseWarningKind::DecimalNumberIsTooBig,
1180 });
1181 return if integer_part == 2047 {
1182 (FixWord::ONE, span_start..span_end)
1183 } else {
1184 (FixWord::ZERO, span_start..span_end)
1185 };
1186 }
1187
1188 let modulus = integer_part
1189 .checked_mul(FixWord::ONE.0)
1190 .unwrap()
1191 .checked_add(fractional_part)
1192 .unwrap();
1193 let result = if negative {
1194 modulus.checked_mul(-1).unwrap()
1195 } else {
1196 modulus
1197 };
1198 (FixWord(result), span_start..input.raw_data_span.start)
1199 }
1200 fn to_string(self, _: &LowerOpts) -> Option<String> {
1201 Some(format!["R {self}"])
1202 }
1203}
1204
1205#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1207#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1208pub enum DesignSize {
1209 Valid(FixWord),
1210 Invalid,
1211}
1212
1213impl Default for DesignSize {
1214 fn default() -> Self {
1215 DesignSize::Valid(FixWord::ONE * 10)
1216 }
1217}
1218
1219impl DesignSize {
1220 pub fn get(&self) -> FixWord {
1221 match self {
1222 DesignSize::Valid(v) => *v,
1223 DesignSize::Invalid => FixWord::ONE * 10,
1224 }
1225 }
1226}
1227
1228impl From<FixWord> for DesignSize {
1229 fn from(value: FixWord) -> Self {
1230 Self::Valid(value)
1231 }
1232}
1233
1234impl Parse for DesignSize {
1235 fn parse(input: &mut Input) -> (Self, Range<usize>) {
1236 let (n, r) = FixWord::parse(input);
1237 let d = if n < FixWord::ONE {
1238 input.errors.push(ParseWarning {
1239 span: r.start..input.raw_data_span.end,
1240 knuth_pltotf_offset: Some(input.raw_data_span.end),
1241 kind: ParseWarningKind::DesignSizeIsTooSmall,
1242 });
1243 DesignSize::Invalid
1244 } else {
1245 DesignSize::Valid(n)
1246 };
1247 (d, r)
1248 }
1249 fn to_string(self, opts: &LowerOpts) -> Option<String> {
1250 match self {
1251 DesignSize::Valid(n) => Parse::to_string(n, opts),
1252 DesignSize::Invalid => Some("D 10".to_string()),
1253 }
1254 }
1255}
1256
1257impl Parse for Option<FixWord> {
1258 fn parse(input: &mut Input) -> (Self, Range<usize>) {
1259 let (n, r) = FixWord::parse(input);
1260 (Some(n), r)
1261 }
1262
1263 fn to_string(self, opts: &LowerOpts) -> Option<String> {
1264 match self {
1265 None => None,
1266 Some(n) => Parse::to_string(n, opts),
1267 }
1268 }
1269}
1270
1271#[derive(Clone)]
1272enum ParseU8Error {
1273 SmallIntegerIsTooBig {
1274 span: std::ops::Range<usize>,
1275 knuth_pltotf_offset: usize,
1276 radix: u8,
1277 },
1278 EmptyCharacterValue {
1279 span: std::ops::Range<usize>,
1280 },
1281 InvalidFaceCode {
1282 span: std::ops::Range<usize>,
1283 },
1284 InvalidPrefixForSmallInteger {
1285 span: std::ops::Range<usize>,
1286 },
1287}
1288
1289impl From<ParseU8Error> for ParseWarning {
1290 fn from(value: ParseU8Error) -> Self {
1291 match value {
1292 ParseU8Error::SmallIntegerIsTooBig {
1293 span,
1294 knuth_pltotf_offset,
1295 radix,
1296 } => ParseWarning {
1297 span,
1298 knuth_pltotf_offset: Some(knuth_pltotf_offset),
1299 kind: ParseWarningKind::SmallIntegerIsTooBig { radix },
1300 },
1301 ParseU8Error::EmptyCharacterValue { span } => ParseWarning {
1302 span: span.clone(),
1303 knuth_pltotf_offset: Some(span.end),
1304 kind: ParseWarningKind::EmptyCharacterValue,
1305 },
1306 ParseU8Error::InvalidFaceCode { span } => ParseWarning {
1307 span: span.clone(),
1308 knuth_pltotf_offset: Some(span.end),
1309 kind: ParseWarningKind::InvalidFaceCode,
1310 },
1311 ParseU8Error::InvalidPrefixForSmallInteger { span } => ParseWarning {
1312 span: span.clone(),
1313 knuth_pltotf_offset: Some(span.end + 1),
1314 kind: ParseWarningKind::InvalidPrefixForSmallInteger,
1315 },
1316 }
1317 }
1318}
1319
1320fn parse_u8(input: &mut Input) -> Result<u8, ParseU8Error> {
1321 let parse_number = |input: &mut Input, radix: u8| {
1323 input.consume_spaces();
1324 let start_span = input.raw_data_span.start;
1325 let mut acc: u8 = 0;
1326 while let Some(c) = input.peek() {
1327 let n: u8 = match c.to_digit(radix as u32) {
1328 None => break,
1329 Some(d) => d.try_into().unwrap(),
1330 };
1331 input.next();
1332 match acc.checked_mul(radix).and_then(|l| l.checked_add(n)) {
1333 None => {
1334 let knuth_pltotf_offset = input.raw_data_span.start;
1338 while let Some(c) = input.peek() {
1339 match c.to_digit(radix as u32) {
1340 None => break,
1341 Some(_) => input.next(),
1342 };
1343 }
1344 let end_span = input.raw_data_span.start;
1345 return Err(ParseU8Error::SmallIntegerIsTooBig {
1346 span: start_span..end_span,
1347 knuth_pltotf_offset,
1348 radix,
1349 });
1350 }
1351 Some(new_acc) => acc = new_acc,
1352 }
1353 }
1354 Ok(acc)
1355 };
1356 let u = match input.next() {
1357 Some('C' | 'c') => {
1359 input.consume_spaces();
1360 match input.next() {
1361 None => {
1362 let span = input.last_span(None);
1363 return Err(ParseU8Error::EmptyCharacterValue { span });
1364 }
1365 Some(c @ ' '..='~') => (c as usize).try_into().unwrap(),
1366 _ => 127,
1368 }
1369 }
1370 Some('D' | 'd') => parse_number(input, 10)?,
1372 Some('O' | 'o') => parse_number(input, 8)?,
1374 Some('H' | 'h') => parse_number(input, 16)?,
1376 Some('F' | 'f') => {
1378 input.consume_spaces();
1379 let span_start = input.raw_data_span.start;
1380 let mut acc: u8 = match input.next() {
1381 Some('M' | 'm') => 0,
1382 Some('B' | 'b') => 2,
1383 Some('L' | 'l') => 4,
1384 _ => 18,
1385 };
1386 acc += match input.next() {
1387 Some('R' | 'r') => 0,
1388 Some('I' | 'i') => 1,
1389 _ => 18,
1390 };
1391 acc += match input.next() {
1392 Some('R' | 'r') => 0,
1393 Some('C' | 'c') => 6,
1394 Some('E' | 'e') => 12,
1395 _ => 18,
1396 };
1397 if acc >= 18 {
1398 let span_end = input.raw_data_span.start;
1399 return Err(ParseU8Error::InvalidFaceCode {
1400 span: span_start..span_end,
1401 });
1402 }
1403 acc
1404 }
1405 c => {
1406 let span = input.last_span(c);
1407 return Err(ParseU8Error::InvalidPrefixForSmallInteger { span });
1408 }
1409 };
1410 Ok(u)
1411}
1412
1413#[cfg(test)]
1414mod tests {
1415 use super::*;
1416
1417 fn run(source: &str, want: Vec<Root>, want_errs: Vec<ParseWarning>) {
1418 let (got, got_errors) = Ast::from_pl_source_code(source);
1419 assert_eq!(got_errors, want_errs);
1420 assert_eq!(got, Ast(want));
1421 }
1422
1423 macro_rules! ast_test {
1424 ( $( ($name: ident, $input: expr, $want: expr, $want_errors: expr, ), )+ ) => {
1425 $(
1426 #[test]
1427 fn $name() {
1428 let input = $input;
1429 let want = $want;
1430 let want_errors = $want_errors;
1431 run(input, want, want_errors);
1432 }
1433 )+
1434 };
1435 }
1436
1437 ast_test!(
1438 (
1439 string,
1440 r"(CODINGSCHEME MY CODING Scheme)",
1441 vec![Root::CodingScheme(SingleValue {
1442 data: "MY CODING Scheme".into(),
1443 data_span: 14..30,
1444 })],
1445 vec![],
1446 ),
1447 (
1448 boolean_true,
1449 r"(SEVENBITSAFEFLAG TRUE)",
1450 vec![Root::SevenBitSafeFlag(SingleValue {
1451 data: true,
1452 data_span: 18..19,
1453 })],
1454 vec![],
1455 ),
1456 (
1457 boolean_true_with_junk,
1458 r"(SEVENBITSAFEFLAG TRIPS)",
1459 vec![Root::SevenBitSafeFlag(SingleValue {
1460 data: true,
1461 data_span: 18..19
1462 })],
1463 vec![],
1464 ),
1465 (
1466 boolean_false,
1467 r"(SEVENBITSAFEFLAG FALSE)",
1468 vec![Root::SevenBitSafeFlag(SingleValue {
1469 data: false,
1470 data_span: 18..19
1471 })],
1472 vec![],
1473 ),
1474 (
1475 boolean_invalid,
1476 r"(SEVENBITSAFEFLAG INVALID)",
1477 vec![],
1478 vec![ParseWarning {
1479 span: 18..25,
1480 knuth_pltotf_offset: Some(19),
1481 kind: ParseWarningKind::InvalidBoolean,
1482 }],
1483 ),
1484 (
1485 one_byte_char_invalid_prefix,
1486 r"(BOUNDARYCHAR J a)",
1487 vec![Root::BoundaryChar(SingleValue {
1488 data: Char(0),
1489 data_span: 14..17
1490 })],
1491 vec![ParseWarning {
1492 span: 14..15,
1493 knuth_pltotf_offset: Some(16),
1494 kind: ParseWarningKind::InvalidPrefixForSmallInteger,
1495 }],
1496 ),
1497 (
1498 one_byte_char_no_prefix,
1499 r"(BOUNDARYCHAR)",
1500 vec![Root::BoundaryChar(SingleValue {
1501 data: Char(0),
1502 data_span: 13..13,
1503 })],
1504 vec![ParseWarning {
1505 span: 13..13,
1506 knuth_pltotf_offset: Some(14),
1507 kind: ParseWarningKind::InvalidPrefixForSmallInteger,
1508 }],
1509 ),
1510 (
1511 one_byte_char,
1512 r"(BOUNDARYCHAR C a)",
1513 vec![Root::BoundaryChar(SingleValue {
1514 data: 'a'.try_into().unwrap(),
1515 data_span: 14..17,
1516 })],
1517 vec![],
1518 ),
1519 (
1520 one_byte_missing,
1521 r"(BOUNDARYCHAR C)",
1522 vec![Root::BoundaryChar(SingleValue {
1523 data: Char(0),
1524 data_span: 14..15
1525 })],
1526 vec![ParseWarning {
1527 span: 15..15,
1528 knuth_pltotf_offset: Some(15),
1529 kind: ParseWarningKind::EmptyCharacterValue,
1530 }],
1531 ),
1532 (
1552 one_byte_octal,
1553 r"(BOUNDARYCHAR O 77)",
1554 vec![Root::BoundaryChar(SingleValue {
1555 data: Char(0o77),
1556 data_span: 14..18
1557 })],
1558 vec![],
1559 ),
1560 (
1561 one_byte_octal_too_big,
1562 r"(BOUNDARYCHAR O 7777)",
1563 vec![Root::BoundaryChar(SingleValue {
1564 data: Char(0o0),
1565 data_span: 14..20
1566 })],
1567 vec![ParseWarning {
1568 span: 16..20,
1569 knuth_pltotf_offset: Some(19),
1570 kind: ParseWarningKind::SmallIntegerIsTooBig { radix: 8 }
1571 }],
1572 ),
1573 (
1574 one_byte_decimal,
1575 r"(BOUNDARYCHAR D 77)",
1576 vec![Root::BoundaryChar(SingleValue {
1577 data: Char(77),
1578 data_span: 14..18
1579 })],
1580 vec![],
1581 ),
1582 (
1583 one_byte_decimal_too_big,
1584 r"(BOUNDARYCHAR D 7777)",
1585 vec![Root::BoundaryChar(SingleValue {
1586 data: Char(0),
1587 data_span: 14..20
1588 })],
1589 vec![ParseWarning {
1590 span: 16..20,
1591 knuth_pltotf_offset: Some(19),
1592 kind: ParseWarningKind::SmallIntegerIsTooBig { radix: 10 }
1593 }],
1594 ),
1595 (
1596 one_byte_hexadecimal,
1597 r"(BOUNDARYCHAR H 17)",
1598 vec![Root::BoundaryChar(SingleValue {
1599 data: Char(0x17),
1600 data_span: 14..18
1601 })],
1602 vec![],
1603 ),
1604 (
1605 one_byte_hexadecimal_too_big,
1606 r"(BOUNDARYCHAR H 1777)",
1607 vec![Root::BoundaryChar(SingleValue {
1608 data: Char(0x0),
1609 data_span: 14..20
1610 })],
1611 vec![ParseWarning {
1612 span: 16..20,
1613 knuth_pltotf_offset: Some(19),
1614 kind: ParseWarningKind::SmallIntegerIsTooBig { radix: 16 }
1615 }],
1616 ),
1617 (
1618 one_byte_face,
1619 r"(BOUNDARYCHAR F BIC)",
1620 vec![Root::BoundaryChar(SingleValue {
1621 data: Char(9),
1622 data_span: 14..19
1623 })],
1624 vec![],
1625 ),
1626 (
1627 one_byte_face_invalid,
1628 r"(BOUNDARYCHAR F ABC)",
1629 vec![Root::BoundaryChar(SingleValue {
1630 data: Char(0),
1631 data_span: 14..19
1632 })],
1633 vec![ParseWarning {
1634 span: 16..19,
1635 knuth_pltotf_offset: Some(19),
1636 kind: ParseWarningKind::InvalidFaceCode,
1637 }],
1638 ),
1639 (
1640 one_byte_four_byte,
1641 r"(Header D19HA)",
1642 vec![Root::Header(TupleValue {
1643 left: DecimalU8(19),
1644 left_span: 8..11,
1645 right: 0xA,
1646 right_span: 11..13,
1647 })],
1648 vec![],
1649 ),
1650 (
1651 four_bytes_octal,
1652 r"(CHECKSUM O 77)",
1653 vec![Root::Checksum(SingleValue {
1654 data: 0o77,
1655 data_span: 10..14
1656 })],
1657 vec![],
1658 ),
1659 (
1660 four_bytes_hexadecimal,
1661 r"(CHECKSUM H 77)",
1662 vec![Root::Checksum(SingleValue {
1663 data: 0x77,
1664 data_span: 10..14
1665 })],
1666 vec![],
1667 ),
1668 (
1669 four_bytes_missing_prefix,
1670 r"(CHECKSUM)",
1671 vec![Root::Checksum(SingleValue {
1672 data: 0,
1673 data_span: 9..9
1674 })],
1675 vec![ParseWarning {
1676 span: 9..9,
1677 knuth_pltotf_offset: Some(9),
1678 kind: ParseWarningKind::InvalidPrefixForInteger { prefix: None },
1679 }],
1680 ),
1681 (
1682 four_bytes_invalid_prefix,
1683 r"(CHECKSUM W 77)",
1684 vec![Root::Checksum(SingleValue {
1685 data: 0,
1686 data_span: 10..11
1687 })],
1688 vec![ParseWarning {
1689 span: 10..11,
1690 knuth_pltotf_offset: Some(11),
1691 kind: ParseWarningKind::InvalidPrefixForInteger { prefix: Some('W') },
1692 }],
1693 ),
1694 (
1695 four_bytes_too_big,
1696 r"(CHECKSUM O 666666666666666666)",
1697 vec![Root::Checksum(SingleValue {
1698 data: 0o6666666666,
1699 data_span: 10..30
1700 })],
1701 vec![ParseWarning {
1702 span: 12..30,
1703 knuth_pltotf_offset: Some(23),
1704 kind: ParseWarningKind::IntegerIsTooBig { radix: 8 }
1705 }],
1706 ),
1707 (
1708 four_bytes_invalid_octal_digit,
1709 r"(CHECKSUM O 666686666666666666)",
1710 vec![Root::Checksum(SingleValue {
1711 data: 0o6666,
1712 data_span: 10..30
1713 })],
1714 vec![ParseWarning {
1715 span: 16..17,
1716 knuth_pltotf_offset: Some(17),
1717 kind: ParseWarningKind::InvalidOctalDigit { invalid_digit: '8' }
1718 }],
1719 ),
1720 (
1721 fix_word_integer,
1722 r"(DESIGNSIZE D 1)",
1723 vec![Root::DesignSize(SingleValue {
1724 data: FixWord::ONE.into(),
1725 data_span: 12..15,
1726 })],
1727 vec![],
1728 ),
1729 (
1730 fix_word_decimal,
1731 r"(DESIGNSIZE D 11.5)",
1732 vec![Root::DesignSize(SingleValue {
1733 data: (FixWord::ONE * 23 / 2).into(),
1734 data_span: 12..18,
1735 })],
1736 vec![],
1737 ),
1738 (
1739 fix_word_negative,
1740 r"(CHARACTER C X (CHARWD D -11.5))",
1741 vec![Root::Character(Branch {
1742 data: Char::X,
1743 data_span: 11..14,
1744 children: vec![Character::Width(SingleValue {
1745 data: Some(FixWord::ONE * -23 / 2),
1746 data_span: 23..30,
1747 })]
1748 }),],
1749 vec![],
1750 ),
1751 (
1752 fix_word_too_big,
1753 r"(DESIGNSIZE D 2047.9999999)",
1754 vec![Root::DesignSize(SingleValue {
1755 data: FixWord::ONE.into(),
1756 data_span: 12..26,
1757 })],
1758 vec![ParseWarning {
1759 span: 14..26,
1760 knuth_pltotf_offset: Some(14),
1761 kind: ParseWarningKind::DecimalNumberIsTooBig,
1762 }],
1763 ),
1764 (
1765 pl_to_tf_section_7_example,
1766 r"
1767 (FAMILY NOVA)
1768 (FACE F MIE)
1769 (CODINGSCHEME ASCII)
1770 (DESIGNSIZE D 10)
1771 (DESIGNUNITS D 18)
1772 (COMMENT A COMMENT IS IGNORED)
1773 (COMMENT (EXCEPT THIS ONE ISN'T))
1774 (COMMENT (ACTUALLY IT IS, EVEN THOUGH
1775 IT SAYS IT ISN'T))
1776 (FONTDIMEN
1777 (SLANT R -.25)
1778 (SPACE D 6)
1779 (SHRINK D 2)
1780 (STRETCH D 3)
1781 (XHEIGHT R 10.55)
1782 (QUAD D 18)
1783 )
1784 (LIGTABLE
1785 (LABEL C f)
1786 (LIG C f O 200)
1787 (SKIP D 1)
1788 (LABEL O 200)
1789 (LIG C i O 201)
1790 (KRN O 51 R 1.5)
1791 (/LIG C ? C f)
1792 (STOP)
1793 )
1794 (CHARACTER C f
1795 (CHARWD D 6)
1796 (CHARHT R 13.5)
1797 (CHARIC R 1.5)
1798 )",
1799 vec![
1800 Root::Family(SingleValue {
1801 data: "NOVA".into(),
1802 data_span: 21..25,
1803 }),
1804 Root::Face(SingleValue {
1805 data: Face::Valid(
1806 crate::FaceWeight::Medium,
1807 crate::FaceSlope::Italic,
1808 crate::FaceExpansion::Extended
1809 ),
1810 data_span: 45..50,
1811 }),
1812 Root::CodingScheme(SingleValue {
1813 data: "ASCII".into(),
1814 data_span: 78..83,
1815 }),
1816 Root::DesignSize(SingleValue {
1817 data: (FixWord::ONE * 10).into(),
1818 data_span: 109..113,
1819 }),
1820 Root::DesignUnits(SingleValue {
1821 data: FixWord::ONE * 18,
1822 data_span: 140..144,
1823 }),
1824 Root::Comment(" A COMMENT IS IGNORED".into()),
1825 Root::Comment(" (EXCEPT THIS ONE ISN'T)".into()),
1826 Root::Comment(format![
1827 " (ACTUALLY IT IS, EVEN THOUGH\n{}IT SAYS IT ISN'T)",
1828 " ".repeat(20)
1829 ]),
1830 Root::FontDimension(Branch {
1831 data: (),
1832 data_span: 362..362,
1833 children: vec![
1834 FontDimension::NamedParam(
1835 NamedParameter::Slant,
1836 SingleValue {
1837 data: FixWord::ONE * -1 / 4,
1838 data_span: 369..375,
1839 }
1840 ),
1841 FontDimension::NamedParam(
1842 NamedParameter::Space,
1843 SingleValue {
1844 data: FixWord::ONE * 6,
1845 data_span: 399..402,
1846 }
1847 ),
1848 FontDimension::NamedParam(
1849 NamedParameter::Shrink,
1850 SingleValue {
1851 data: FixWord::ONE * 2,
1852 data_span: 427..430,
1853 }
1854 ),
1855 FontDimension::NamedParam(
1856 NamedParameter::Stretch,
1857 SingleValue {
1858 data: FixWord::ONE * 3,
1859 data_span: 456..459,
1860 }
1861 ),
1862 FontDimension::NamedParam(
1863 NamedParameter::XHeight,
1864 SingleValue {
1865 data: FixWord(1055 * FixWord::ONE.0 / 100 + 1),
1866 data_span: 485..492,
1867 }
1868 ),
1869 FontDimension::NamedParam(
1870 NamedParameter::Quad,
1871 SingleValue {
1872 data: FixWord::ONE * 18,
1873 data_span: 515..519,
1874 }
1875 ),
1876 ]
1877 }),
1878 Root::LigTable(Branch {
1879 data: (),
1880 data_span: 575..575,
1881 children: vec![
1882 LigTable::Label(SingleValue {
1883 data: LigTableLabel::Char('f'.try_into().unwrap()),
1884 data_span: 582..585,
1885 }),
1886 LigTable::Lig(
1887 PostLigOperation::RetainNeitherMoveToInserted,
1888 TupleValue {
1889 left: 'f'.try_into().unwrap(),
1890 left_span: 607..610,
1891 right: Char(0o200),
1892 right_span: 611..616,
1893 }
1894 ),
1895 LigTable::Skip(SingleValue {
1896 data: DecimalU8(1),
1897 data_span: 639..642
1898 }),
1899 LigTable::Label(SingleValue {
1900 data: LigTableLabel::Char(Char(0o200)),
1901 data_span: 666..671,
1902 }),
1903 LigTable::Lig(
1904 PostLigOperation::RetainNeitherMoveToInserted,
1905 TupleValue {
1906 left: 'i'.try_into().unwrap(),
1907 left_span: 693..696,
1908 right: Char(0o201),
1909 right_span: 697..702,
1910 }
1911 ),
1912 LigTable::Kern(TupleValue {
1913 left: Char(0o51),
1914 left_span: 724..728,
1915 right: FixWord::ONE * 3 / 2,
1916 right_span: 729..734,
1917 }),
1918 LigTable::Lig(
1919 PostLigOperation::RetainLeftMoveNowhere,
1920 TupleValue {
1921 left: '?'.try_into().unwrap(),
1922 left_span: 757..760,
1923 right: 'f'.try_into().unwrap(),
1924 right_span: 761..764,
1925 }
1926 ),
1927 LigTable::Stop(SingleValue {
1928 data: (),
1929 data_span: 786..786,
1930 }),
1931 ]
1932 }),
1933 Root::Character(Branch {
1934 data: 'f'.try_into().unwrap(),
1935 data_span: 828..831,
1936 children: vec![
1937 Character::Width(SingleValue {
1938 data: Some(FixWord::ONE * 6),
1939 data_span: 855..858,
1940 }),
1941 Character::Height(SingleValue {
1942 data: FixWord::ONE * 27 / 2,
1943 data_span: 883..889,
1944 }),
1945 Character::ItalicCorrection(SingleValue {
1946 data: FixWord::ONE * 3 / 2,
1947 data_span: 914..919,
1948 }),
1949 ]
1950 })
1951 ],
1952 vec![],
1953 ),
1954 );
1955}