1use std::convert::TryFrom;
11use std::ops::Range;
12
13use smol_str::SmolStr;
14use write_fonts::types::Fixed;
15
16use crate::{Kind, Node, NodeOrToken};
17
18use super::{ChildIter, Token};
19
20pub trait AstNode {
24 fn cast(node: &NodeOrToken) -> Option<Self>
26 where
27 Self: Sized;
28
29 fn range(&self) -> Range<usize>;
33
34 fn iter(&self) -> ChildIter<'_> {
36 Default::default()
37 }
38}
39
40macro_rules! ast_token {
42 ($typ:ident, $kind:expr) => {
43 #[derive(Clone, Debug)]
44 #[allow(missing_docs)]
45 pub struct $typ {
46 inner: Token,
47 }
48
49 impl $typ {
50 #[allow(unused)]
52 pub fn text(&self) -> &SmolStr {
53 &self.inner.text
54 }
55
56 #[allow(unused)]
58 pub fn token(&self) -> &Token {
59 &self.inner
60 }
61
62 #[allow(dead_code)]
64 pub(crate) fn node_(&self) -> Option<&Node> {
65 None
66 }
67 }
68
69 impl AstNode for $typ {
70 fn cast(node: &NodeOrToken) -> Option<Self> {
71 if let NodeOrToken::Token(t) = node {
72 if t.kind == $kind {
73 return Some(Self { inner: t.clone() });
74 }
75 }
76 None
77 }
78
79 fn range(&self) -> std::ops::Range<usize> {
80 self.inner.range()
81 }
82 }
83 };
84}
85
86macro_rules! ast_node {
88 ($typ:ident, $kind:expr) => {
89 #[derive(Clone, Debug)]
90 #[allow(missing_docs)]
91 pub struct $typ {
92 inner: Node,
93 }
94
95 impl $typ {
96 pub(crate) fn try_from_node(node: &Node) -> Option<Self> {
97 if node.kind == $kind {
98 return Some(Self {
99 inner: node.clone(),
100 });
101 }
102 None
103 }
104
105 #[allow(dead_code)]
106 pub(crate) fn find_token(&self, kind: Kind) -> Option<&Token> {
107 self.iter()
108 .find(|t| t.kind() == kind)
109 .and_then(NodeOrToken::as_token)
110 }
111
112 #[allow(dead_code)]
114 pub fn node(&self) -> &Node {
115 &self.inner
116 }
117
118 #[allow(dead_code)]
120 pub(crate) fn node_(&self) -> Option<&Node> {
121 Some(&self.inner)
122 }
123 }
124
125 impl AstNode for $typ {
126 fn cast(node: &NodeOrToken) -> Option<Self> {
127 if let NodeOrToken::Node(inner) = node {
128 return Self::try_from_node(inner);
129 }
130 None
131 }
132
133 fn range(&self) -> std::ops::Range<usize> {
134 self.inner.range()
135 }
136
137 fn iter(&self) -> ChildIter<'_> {
138 self.inner.iter_children()
139 }
140 }
141 };
142}
143
144macro_rules! ast_enum {
149 ($typ:ident{ $($name:ident($member:ident),)*}) => {
150 #[derive(Clone, Debug)]
151 #[allow(missing_docs)]
152 pub enum $typ {
153 $($name($member)),*
154 }
155
156 impl AstNode for $typ {
157 fn cast(node: &NodeOrToken) -> Option<Self> {
158 $(
159 if let Some(thing) = $member::cast(node) {
160 return Some(Self::$name(thing));
161 }
162 )*
163 None
164
165 }
166
167 fn range(&self) -> std::ops::Range<usize> {
168 match self {
169 $(
170 Self::$name(inner) => inner.range(),
171 )*
172 }
173 }
174 }
175
176 impl $typ {
177 #[allow(unused)]
178 pub(crate) fn node(&self) -> Option<&Node> {
179 match self {
180 $(
181 Self::$name(inner) => inner.node_(),
182 )*
183 }
184 }
185
186 #[allow(dead_code)]
188 pub(crate) fn node_(&self) -> Option<&Node> {
189 self.node()
190 }
191
192 }
193 };
194
195}
196
197ast_token!(Cid, Kind::Cid);
198ast_token!(GlyphName, Kind::GlyphName);
199ast_token!(Tag, Kind::Tag);
200ast_token!(GlyphClassName, Kind::NamedGlyphClass);
201ast_token!(Number, Kind::Number);
202ast_token!(Float, Kind::Float);
203ast_token!(Octal, Kind::Octal);
204ast_token!(Hex, Kind::Hex);
205ast_token!(Null, Kind::NullKw);
206ast_node!(Root, Kind::SourceFile);
207ast_node!(GlyphRange, Kind::GlyphRange);
208ast_node!(GlyphClassDef, Kind::GlyphClassDefNode);
209ast_node!(MarkClassDef, Kind::MarkClassNode);
210ast_node!(Anchor, Kind::AnchorNode);
211ast_node!(AnchorDef, Kind::AnchorDefNode);
212ast_node!(ValueRecordDef, Kind::ValueRecordDefNode);
213ast_node!(GlyphClassLiteral, Kind::GlyphClass);
214ast_node!(LanguageSystem, Kind::LanguageSystemNode);
215ast_node!(Include, Kind::IncludeNode);
216ast_node!(Feature, Kind::FeatureNode);
217ast_node!(Script, Kind::ScriptNode);
218ast_node!(Language, Kind::LanguageNode);
219ast_node!(LookupFlag, Kind::LookupFlagNode);
220ast_node!(LookupRef, Kind::LookupRefNode);
221ast_node!(LookupBlock, Kind::LookupBlockNode);
222ast_node!(ValueRecord, Kind::ValueRecordNode);
223ast_node!(Device, Kind::DeviceNode);
224ast_node!(SizeMenuName, Kind::SizeMenuNameNode);
225ast_node!(Parameters, Kind::ParametersNode);
226ast_node!(FeatureNames, Kind::FeatureNamesKw);
227ast_node!(CvParameters, Kind::CvParametersKw);
228ast_node!(CvParametersName, Kind::CvParamsNameNode);
229ast_node!(CvParametersChar, Kind::CharacterKw);
230
231ast_node!(HeadTable, Kind::HeadTableNode);
232ast_node!(HheaTable, Kind::HheaTableNode);
233ast_node!(NameTable, Kind::NameTableNode);
234ast_node!(BaseTable, Kind::BaseTableNode);
235ast_node!(GdefTable, Kind::GdefTableNode);
236ast_node!(Os2Table, Kind::Os2TableNode);
237ast_node!(VheaTable, Kind::VheaTableNode);
238ast_node!(VmtxTable, Kind::VmtxTableNode);
239ast_node!(StatTable, Kind::StatTableNode);
240ast_node!(UnimplentedTable, Kind::TableNode);
241
242ast_enum!(Table {
243 Head(HeadTable),
244 Hhea(HheaTable),
245 Name(NameTable),
246 Base(BaseTable),
247 Gdef(GdefTable),
248 Os2(Os2Table),
249 Vhea(VheaTable),
250 Vmtx(VmtxTable),
251 Stat(StatTable),
252 Other(UnimplentedTable),
253});
254
255ast_node!(BaseTagList, Kind::BaseTagListNode);
256ast_node!(BaseScriptList, Kind::BaseScriptListNode);
257ast_node!(ScriptRecord, Kind::ScriptRecordNode);
258
259ast_node!(MetricRecord, Kind::MetricValueNode);
260ast_node!(NumberRecord, Kind::NumberValueNode);
261ast_node!(VendorRecord, Kind::Os2VendorNode);
262ast_node!(NameRecord, Kind::NameRecordNode);
263ast_node!(NameSpec, Kind::NameSpecNode);
264ast_node!(VmtxEntry, Kind::VmtxEntryNode);
265
266ast_enum!(DecOctHex {
267 Decimal(Number),
268 Octal(Octal),
269 Hex(Hex),
270});
271
272ast_enum!(FloatLike {
273 Float(Float),
274 Number(Number),
275});
276
277ast_node!(ConditionSet, Kind::ConditionSetNode);
278ast_node!(Condition, Kind::ConditionNode);
279ast_node!(FeatureVariation, Kind::VariationNode);
280ast_node!(VariableMetric, Kind::VariableMetricNode);
281ast_node!(LocationValue, Kind::LocationValueNode);
282ast_node!(LocationSpec, Kind::LocationSpecNode);
283ast_node!(LocationSpecItem, Kind::LocationSpecItemNode);
284ast_enum!(Metric {
285 Scalar(Number),
286 Variable(VariableMetric),
287 GlyphsAppNumber(GlyphsAppNumber),
288});
289ast_node!(AxisLocation, Kind::AxisLocationNode);
290ast_token!(NumberSuffix, Kind::NumberSuffix);
291
292ast_node!(GdefClassDef, Kind::GdefClassDefNode);
293ast_node!(GdefClassDefEntry, Kind::GdefClassDefEntryNode);
294ast_node!(GdefAttach, Kind::GdefAttachNode);
295ast_node!(GdefLigatureCaret, Kind::GdefLigatureCaretNode);
296
297ast_enum!(GdefTableItem {
298 ClassDef(GdefClassDef),
299 Attach(GdefAttach),
300 LigatureCaret(GdefLigatureCaret),
301});
302
303ast_node!(HeadFontRevision, Kind::HeadFontRevisionNode);
304
305ast_node!(Os2NumberList, Kind::Os2NumberListNode);
306ast_node!(Os2FamilyClass, Kind::Os2FamilyClassNode);
307ast_enum!(Os2TableItem {
308 Number(NumberRecord),
309 NumberList(Os2NumberList),
310 Metric(MetricRecord),
311 Vendor(VendorRecord),
312 FamilyClass(Os2FamilyClass),
313});
314
315ast_node!(StatElidedFallbackName, Kind::StatElidedFallbackNameNode);
316ast_node!(StatDesignAxis, Kind::StatDesignAxisNode);
317ast_node!(StatAxisValue, Kind::StatAxisValueNode);
318
319ast_enum!(StatTableItem {
320 ElidedFallbackName(StatElidedFallbackName),
321 DesignAxis(StatDesignAxis),
322 AxisValue(StatAxisValue),
323});
324
325ast_node!(StatAxisFlag, Kind::StatAxisValueFlagNode);
326ast_node!(StatAxisLocation, Kind::StatAxisValueLocationNode);
327
328ast_enum!(StatAxisValueItem {
329 NameRecord(NameSpec),
330 Flag(StatAxisFlag),
331 Location(StatAxisLocation),
332});
333
334ast_node!(FeatureRef, Kind::AaltFeatureNode);
335
336ast_node!(Gsub1, Kind::GsubType1);
337ast_node!(Gsub2, Kind::GsubType2);
338ast_node!(Gsub3, Kind::GsubType3);
339ast_node!(Gsub4, Kind::GsubType4);
340ast_node!(Gsub5, Kind::GsubType5);
341ast_node!(Gsub6, Kind::GsubType6);
342ast_node!(Gsub8, Kind::GsubType8);
343ast_node!(GsubIgnore, Kind::GsubIgnore);
344
345ast_node!(Gpos1, Kind::GposType1);
346ast_node!(Gpos2, Kind::GposType2);
347ast_node!(Gpos3, Kind::GposType3);
348ast_node!(Gpos4, Kind::GposType4);
349ast_node!(Gpos5, Kind::GposType5);
350ast_node!(Gpos6, Kind::GposType6);
351ast_node!(Gpos8, Kind::GposType8);
352ast_node!(GposIgnore, Kind::GposIgnore);
353ast_node!(AnchorMark, Kind::AnchorMarkNode);
354ast_node!(LigatureComponent, Kind::LigatureComponentNode);
355
356ast_node!(BacktrackSequence, Kind::BacktrackSequence);
357ast_node!(LookaheadSequence, Kind::LookaheadSequence);
358ast_node!(InputSequence, Kind::ContextSequence);
359ast_node!(InputItem, Kind::ContextGlyphNode);
360ast_node!(InlineSubRule, Kind::InlineSubNode);
361ast_node!(IgnoreRule, Kind::IgnoreRuleStatementNode);
362
363ast_enum!(GposStatement {
364 Type1(Gpos1),
365 Type2(Gpos2),
366 Type3(Gpos3),
367 Type4(Gpos4),
368 Type5(Gpos5),
369 Type6(Gpos6),
370 Type8(Gpos8),
371 Ignore(GposIgnore),
372});
373
374ast_enum!(GsubStatement {
375 Type1(Gsub1),
376 Type2(Gsub2),
377 Type3(Gsub3),
378 Type4(Gsub4),
379 Type5(Gsub5),
380 Type6(Gsub6),
381 Type8(Gsub8),
382 Ignore(GsubIgnore),
383});
384
385ast_enum!(GlyphOrClass {
386 Glyph(GlyphName),
387 Cid(Cid),
388 NamedClass(GlyphClassName),
389 Class(GlyphClassLiteral),
390 Null(Null),
391});
392
393ast_enum!(Glyph {
394 Named(GlyphName),
395 Cid(Cid),
396 Null(Null),
397});
398
399ast_enum!(GlyphClass {
400 Named(GlyphClassName),
401 Literal(GlyphClassLiteral),
402});
403
404ast_node!(GlyphsAppNumber, Kind::GlyphsNumberValueNode);
406ast_node!(GlyphsAppNumberExpr, Kind::GlyphsNumberValueExprNode);
407ast_token!(GlyphsAppNumberName, Kind::GlyphsNumberIdent);
408ast_token!(GlyphsAppOperatorPlus, Kind::Plus);
409ast_token!(GlyphsAppOperatorMinus, Kind::Hyphen);
410ast_token!(GlyphsAppOperatorMul, Kind::Asterisk);
411ast_token!(GlyphsAppOperatorDiv, Kind::Slash);
412
413ast_enum!(GlyphsAppOperator {
414 Plus(GlyphsAppOperatorPlus),
415 Minus(GlyphsAppOperatorMinus),
416 Mul(GlyphsAppOperatorMul),
417 Div(GlyphsAppOperatorDiv),
418});
419
420ast_enum!(GlyphsAppExprItem {
421 Ident(GlyphsAppNumberName),
422 Lit(FloatLike),
423 Operator(GlyphsAppOperator),
424});
425
426ast_enum!(GlyphsAppNumberValue {
427 Expr(GlyphsAppNumberExpr),
428 Ident(GlyphsAppNumberName),
429});
430
431pub trait ContextualRuleNode: AstNode {
436 fn backtrack(&self) -> BacktrackSequence {
438 self.iter().find_map(BacktrackSequence::cast).unwrap()
439 }
440
441 fn lookahead(&self) -> LookaheadSequence {
443 self.iter().find_map(LookaheadSequence::cast).unwrap()
444 }
445
446 fn input(&self) -> InputSequence {
448 self.iter().find_map(InputSequence::cast).unwrap()
449 }
450}
451
452impl ContextualRuleNode for Gpos8 {}
453impl ContextualRuleNode for Gsub6 {}
454impl ContextualRuleNode for Gsub8 {}
455impl ContextualRuleNode for IgnoreRule {}
456
457impl Root {
458 pub fn statements(&self) -> impl Iterator<Item = &NodeOrToken> {
460 self.iter().filter(|t| !t.kind().is_trivia())
461 }
462}
463
464impl LanguageSystem {
465 pub fn script(&self) -> Tag {
467 self.inner.iter_children().find_map(Tag::cast).unwrap()
468 }
469
470 pub fn language(&self) -> Tag {
472 self.inner
473 .iter_children()
474 .skip_while(|t| t.kind() != Kind::Tag)
475 .skip(1)
476 .find_map(Tag::cast)
477 .unwrap()
478 }
479}
480
481impl Include {
482 pub(crate) fn path(&self) -> &Token {
483 self.find_token(Kind::Path).unwrap()
484 }
485}
486
487impl Tag {
488 pub(crate) fn parse(&self) -> Result<write_fonts::types::Tag, write_fonts::types::InvalidTag> {
489 self.inner.text.parse()
490 }
491
492 pub fn to_raw(&self) -> write_fonts::types::Tag {
494 self.parse().expect("tag is exactly 4 bytes")
495 }
496}
497
498impl GlyphClassDef {
499 pub(crate) fn class_name(&self) -> GlyphClassName {
500 self.inner
501 .iter_children()
502 .find_map(GlyphClassName::cast)
503 .unwrap()
504 }
505
506 pub(crate) fn class_alias(&self) -> Option<GlyphClassName> {
507 self.iter()
509 .skip_while(|t| t.kind() != Kind::Eq)
510 .find_map(GlyphClassName::cast)
511 }
512
513 pub(crate) fn class_def(&self) -> Option<GlyphClassLiteral> {
514 self.inner.iter_children().find_map(GlyphClassLiteral::cast)
515 }
516}
517
518impl GlyphClassLiteral {
519 pub(crate) fn items(&self) -> impl Iterator<Item = &NodeOrToken> {
520 self.iter()
521 .skip_while(|t| t.kind() != Kind::LSquare)
522 .skip(1)
523 .take_while(|t| t.kind() != Kind::RSquare)
524 .filter(|t| !t.kind().is_trivia())
525 }
526}
527
528impl Cid {
529 pub(crate) fn parse(&self) -> u16 {
530 self.inner.text.parse().expect("cid is already validated")
531 }
532}
533
534impl GlyphRange {
535 pub(crate) fn start(&self) -> &Token {
536 self.iter()
537 .find(|i| i.kind() == Kind::Cid || i.kind() == Kind::GlyphName)
538 .and_then(NodeOrToken::as_token)
539 .unwrap()
540 }
541
542 pub(crate) fn end(&self) -> &Token {
543 self.iter()
544 .skip_while(|t| t.kind() != Kind::Hyphen)
545 .find(|i| i.kind() == Kind::Cid || i.kind() == Kind::GlyphName)
546 .and_then(NodeOrToken::as_token)
547 .unwrap()
548 }
549}
550
551impl GlyphOrClass {
552 pub(crate) fn is_class(&self) -> bool {
553 matches!(self, GlyphOrClass::Class(_) | GlyphOrClass::NamedClass(_))
554 }
555}
556
557impl MarkClassDef {
558 pub(crate) fn keyword(&self) -> &Token {
559 self.find_token(Kind::MarkClassKw).unwrap()
560 }
561
562 pub(crate) fn glyph_class(&self) -> GlyphOrClass {
563 self.iter().find_map(GlyphOrClass::cast).expect("validated")
564 }
565
566 pub(crate) fn anchor(&self) -> Anchor {
567 self.iter().find_map(Anchor::cast).unwrap()
568 }
569
570 pub(crate) fn mark_class_name(&self) -> GlyphClassName {
571 self.iter()
572 .skip_while(|t| t.kind() != Kind::AnchorNode)
573 .find_map(GlyphClassName::cast)
574 .unwrap()
575 }
576}
577
578impl ValueRecordDef {
579 pub(crate) fn value_record(&self) -> ValueRecord {
580 self.iter().find_map(ValueRecord::cast).unwrap()
581 }
582
583 pub(crate) fn name(&self) -> &Token {
584 self.find_token(Kind::Ident).expect("validated")
585 }
586}
587
588impl AnchorDef {
589 pub(crate) fn anchor(&self) -> Anchor {
590 self.iter().find_map(Anchor::cast).unwrap()
591 }
592
593 pub(crate) fn name(&self) -> &Token {
594 self.find_token(Kind::Ident).expect("pre-validated")
595 }
596}
597
598impl Anchor {
599 pub(crate) fn coords(&self) -> Option<(Metric, Metric)> {
600 let tokens = self.iter();
601 let mut first = None;
602
603 for token in tokens {
604 if let Some(metric) = Metric::cast(token) {
605 if let Some(prev) = first.take() {
606 return Some((prev, metric));
607 } else {
608 first = Some(metric);
609 }
610 }
611 }
612 None
613 }
614
615 pub(crate) fn contourpoint(&self) -> Option<Number> {
616 self.iter()
617 .skip_while(|x| x.kind() != Kind::ContourpointKw)
618 .find_map(Number::cast)
619 }
620
621 pub(crate) fn devices(&self) -> Option<(Device, Device)> {
622 let mut iter = self.iter().filter_map(Device::cast);
623 iter.next()
624 .map(|first| (first, iter.next().expect("one device implies another")))
625 }
626
627 pub(crate) fn null(&self) -> Option<&Token> {
628 self.find_token(Kind::NullKw)
629 }
630
631 pub(crate) fn name(&self) -> Option<&Token> {
632 self.find_token(Kind::Ident)
633 }
634}
635
636impl Number {
637 pub(crate) fn parse_signed(&self) -> i16 {
638 self.text().parse().expect("already validated")
639 }
640
641 pub(crate) fn parse_unsigned(&self) -> Option<u16> {
642 self.text().parse().ok()
643 }
644}
645
646impl Float {
647 pub(crate) fn parse(&self) -> f64 {
648 self.text().parse().unwrap()
649 }
650
651 pub(crate) fn parse_fixed(&self) -> Fixed {
652 Fixed::from_f64(self.parse())
653 }
654}
655
656impl FloatLike {
657 pub(crate) fn parse(&self) -> f64 {
658 match self {
659 FloatLike::Number(n) => n.parse_signed() as _,
660 FloatLike::Float(n) => n.parse(),
661 }
662 }
663
664 pub(crate) fn parse_fixed(&self) -> Fixed {
665 Fixed::from_f64(self.parse() as _)
666 }
667}
668
669impl Feature {
670 pub fn tag(&self) -> Tag {
672 self.iter().find_map(Tag::cast).unwrap()
673 }
674
675 pub fn has_insert_marker(&self) -> bool {
677 self.statements().any(|s| s.kind() == Kind::Comment)
678 }
679
680 pub(crate) fn statements(&self) -> impl Iterator<Item = &NodeOrToken> {
681 fn filter_trivia_except_for_magic_insertion_comments(item: &&NodeOrToken) -> bool {
682 match item.kind() {
683 Kind::Comment => item
684 .token_text()
685 .unwrap_or_default()
686 .trim_start()
687 .starts_with("# Automatic Code"),
689 other => !other.is_trivia(),
690 }
691 }
692
693 self.iter()
694 .skip_while(|t| t.kind() != Kind::LBrace)
695 .skip(1)
696 .filter(filter_trivia_except_for_magic_insertion_comments)
697 .take_while(|t| t.kind() != Kind::RBrace)
698 }
699}
700
701impl LookupBlock {
702 #[allow(unused)]
703 pub(crate) fn use_extension(&self) -> Option<&Token> {
705 self.iter()
706 .take_while(|t| t.kind() != Kind::LBrace)
707 .find(|t| t.kind() == Kind::UseExtensionKw)
708 .and_then(NodeOrToken::as_token)
709 }
710
711 pub(crate) fn keyword(&self) -> &Token {
712 self.find_token(Kind::LookupKw).unwrap()
713 }
714
715 pub(crate) fn label(&self) -> &Token {
716 self.find_token(Kind::Label).unwrap()
717 }
718
719 pub(crate) fn statements(&self) -> impl Iterator<Item = &NodeOrToken> {
720 self.iter()
721 .skip_while(|t| t.kind() != Kind::LBrace)
722 .skip(1)
723 .filter(|t| !t.kind().is_trivia())
724 .take_while(|t| t.kind() != Kind::RBrace)
725 }
726}
727
728impl ConditionSet {
729 pub(crate) fn keyword(&self) -> &Token {
730 self.find_token(Kind::ConditionSetKw).unwrap()
731 }
732
733 pub(crate) fn label(&self) -> &Token {
734 self.find_token(Kind::Label).unwrap()
735 }
736
737 pub(crate) fn conditions(&self) -> impl Iterator<Item = Condition> + '_ {
738 self.iter().filter_map(Condition::cast)
739 }
740}
741
742impl Condition {
743 pub(crate) fn tag(&self) -> Tag {
744 self.iter().find_map(Tag::cast).unwrap()
745 }
746
747 pub(crate) fn min_value(&self) -> Number {
748 self.iter().find_map(Number::cast).unwrap()
749 }
750
751 pub(crate) fn max_value(&self) -> Number {
752 self.iter().filter_map(Number::cast).nth(1).unwrap()
753 }
754}
755
756impl FeatureVariation {
757 pub(crate) fn tag(&self) -> Tag {
758 self.iter().find_map(Tag::cast).unwrap()
759 }
760
761 pub(crate) fn condition_set(&self) -> Option<&Token> {
763 self.find_token(Kind::Label)
764 }
765
766 pub(crate) fn null(&self) -> Option<&Token> {
767 self.find_token(Kind::NullKw)
768 }
769
770 pub(crate) fn statements(&self) -> impl Iterator<Item = &NodeOrToken> {
771 self.iter()
772 .skip_while(|t| t.kind() != Kind::LBrace)
773 .skip(1)
774 .filter(|t| !t.kind().is_trivia())
775 .take_while(|t| t.kind() != Kind::RBrace)
776 }
777}
778
779impl Script {
780 pub(crate) fn tag(&self) -> Tag {
781 self.iter().find_map(Tag::cast).unwrap()
782 }
783}
784
785impl Language {
786 pub(crate) fn tag(&self) -> Tag {
787 self.iter().find_map(Tag::cast).unwrap()
788 }
789
790 #[allow(unused)]
792 pub(crate) fn include_dflt(&self) -> Option<&Token> {
793 self.find_token(Kind::IncludeDfltKw)
794 }
795
796 pub(crate) fn exclude_dflt(&self) -> Option<&Token> {
797 self.find_token(Kind::ExcludeDfltKw)
798 }
799
800 pub(crate) fn required(&self) -> Option<&Token> {
801 self.find_token(Kind::RequiredKw)
802 }
803}
804
805impl LookupFlag {
806 pub(crate) fn number(&self) -> Option<Number> {
807 self.iter().find_map(Number::cast)
808 }
809
810 pub(crate) fn values(&self) -> impl Iterator<Item = &NodeOrToken> + '_ {
811 self.iter()
812 .skip(1)
813 .take_while(|t| t.kind() != Kind::Number && t.kind() != Kind::Semi)
814 .filter(|t| !t.kind().is_trivia())
815 }
816}
817
818impl LookupRef {
819 pub(crate) fn label(&self) -> &Token {
820 self.find_token(Kind::Ident).unwrap()
821 }
822}
823
824impl Gsub1 {
825 pub(crate) fn target(&self) -> GlyphOrClass {
826 self.iter().find_map(GlyphOrClass::cast).unwrap()
827 }
828
829 pub(crate) fn replacement(&self) -> Option<GlyphOrClass> {
830 self.iter()
831 .skip_while(|t| t.kind() != Kind::ByKw)
832 .find_map(GlyphOrClass::cast)
833 }
834}
835
836impl Gsub2 {
837 pub(crate) fn target(&self) -> Glyph {
838 self.iter().find_map(Glyph::cast).unwrap()
839 }
840
841 pub(crate) fn replacement(&self) -> impl Iterator<Item = Glyph> + '_ {
842 self.iter()
843 .skip_while(|t| t.kind() != Kind::ByKw)
844 .skip(1)
845 .filter_map(Glyph::cast)
846 }
847}
848
849impl Gsub3 {
850 pub(crate) fn target(&self) -> Glyph {
851 self.iter().find_map(Glyph::cast).unwrap()
852 }
853
854 pub(crate) fn alternates(&self) -> GlyphClass {
855 self.iter()
856 .skip_while(|t| t.kind() != Kind::FromKw)
857 .find_map(GlyphClass::cast)
858 .unwrap()
859 }
860}
861
862impl Gsub4 {
863 pub(crate) fn target(&self) -> impl Iterator<Item = GlyphOrClass> + '_ {
864 self.iter()
865 .take_while(|t| t.kind() != Kind::ByKw)
866 .filter_map(GlyphOrClass::cast)
867 }
868
869 pub(crate) fn replacement(&self) -> Glyph {
870 self.iter()
871 .skip_while(|t| t.kind() != Kind::ByKw)
872 .find_map(Glyph::cast)
873 .unwrap()
874 }
875}
876
877impl Gsub6 {
878 pub(crate) fn inline_rule(&self) -> Option<InlineSubRule> {
879 self.iter().find_map(InlineSubRule::cast)
880 }
881}
882
883impl Gsub8 {
884 pub(crate) fn inline_rule(&self) -> Option<InlineSubRule> {
885 self.iter().find_map(InlineSubRule::cast)
886 }
887}
888
889impl GsubIgnore {
890 pub(crate) fn rules(&self) -> impl Iterator<Item = IgnoreRule> + '_ {
891 self.iter().filter_map(IgnoreRule::cast)
892 }
893}
894
895impl BacktrackSequence {
896 pub(crate) fn items(&self) -> impl Iterator<Item = GlyphOrClass> + '_ {
897 self.iter().filter_map(GlyphOrClass::cast)
898 }
899}
900
901impl LookaheadSequence {
902 pub(crate) fn items(&self) -> impl Iterator<Item = GlyphOrClass> + '_ {
903 self.iter().filter_map(GlyphOrClass::cast)
904 }
905}
906
907impl InputSequence {
908 pub(crate) fn items(&self) -> impl Iterator<Item = InputItem> + '_ {
909 self.iter().filter_map(InputItem::cast)
910 }
911}
912
913impl InputItem {
914 pub(crate) fn target(&self) -> GlyphOrClass {
915 self.iter().find_map(GlyphOrClass::cast).unwrap()
916 }
917
918 pub(crate) fn lookups(&self) -> impl Iterator<Item = LookupRef> + '_ {
919 self.iter().filter_map(LookupRef::cast)
920 }
921
922 pub(crate) fn valuerecord(&self) -> Option<ValueRecord> {
924 self.iter().find_map(ValueRecord::cast)
925 }
926}
927
928impl InlineSubRule {
929 pub(crate) fn replacement_class(&self) -> Option<GlyphClass> {
930 self.iter().find_map(GlyphClass::cast)
931 }
932
933 pub(crate) fn replacement_glyphs(&self) -> impl Iterator<Item = Glyph> + '_ {
935 self.iter().filter_map(Glyph::cast)
936 }
937
938 pub(crate) fn replacements(&self) -> impl Iterator<Item = GlyphOrClass> + '_ {
940 self.iter().filter_map(GlyphOrClass::cast)
941 }
942
943 pub(crate) fn null(&self) -> Option<Null> {
944 self.iter().find_map(Null::cast)
945 }
946}
947
948impl Gpos1 {
949 pub(crate) fn target(&self) -> GlyphOrClass {
950 self.iter().find_map(GlyphOrClass::cast).unwrap()
951 }
952
953 pub(crate) fn value(&self) -> ValueRecord {
954 self.iter().find_map(ValueRecord::cast).unwrap()
955 }
956}
957
958impl Gpos2 {
959 pub(crate) fn enum_(&self) -> Option<&Token> {
960 self.iter()
961 .take_while(|t| t.kind() != Kind::PosKw)
962 .find(|t| t.kind() == Kind::EnumKw)
963 .and_then(NodeOrToken::as_token)
964 }
965
966 pub(crate) fn first_item(&self) -> GlyphOrClass {
967 self.iter().find_map(GlyphOrClass::cast).unwrap()
968 }
969
970 pub(crate) fn second_item(&self) -> GlyphOrClass {
971 self.iter().filter_map(GlyphOrClass::cast).nth(1).unwrap()
972 }
973
974 pub(crate) fn first_value(&self) -> ValueRecord {
975 self.iter().find_map(ValueRecord::cast).unwrap()
976 }
977
978 pub(crate) fn second_value(&self) -> Option<ValueRecord> {
979 self.iter().filter_map(ValueRecord::cast).nth(1)
980 }
981}
982
983impl Gpos3 {
984 pub(crate) fn target(&self) -> GlyphOrClass {
985 self.iter()
986 .filter(|t| !t.kind().is_trivia())
987 .nth(2)
988 .and_then(GlyphOrClass::cast)
989 .unwrap()
990 }
991
992 pub(crate) fn entry(&self) -> Anchor {
993 self.iter().skip(3).find_map(Anchor::cast).unwrap()
994 }
995
996 pub(crate) fn exit(&self) -> Anchor {
997 self.iter()
998 .skip_while(|t| t.kind() != Kind::AnchorNode)
999 .skip(1)
1000 .find_map(Anchor::cast)
1001 .unwrap()
1002 }
1003}
1004
1005impl Gpos4 {
1006 pub(crate) fn base(&self) -> GlyphOrClass {
1007 self.iter()
1008 .filter(|t| !t.kind().is_trivia())
1009 .nth(2)
1010 .and_then(GlyphOrClass::cast)
1011 .unwrap()
1012 }
1013
1014 pub(crate) fn attachments(&self) -> impl Iterator<Item = AnchorMark> + '_ {
1015 self.iter().skip(3).filter_map(AnchorMark::cast)
1016 }
1017}
1018
1019impl Gpos5 {
1020 pub(crate) fn base(&self) -> GlyphOrClass {
1021 self.iter()
1022 .filter(|t| !t.kind().is_trivia())
1023 .nth(2)
1024 .and_then(GlyphOrClass::cast)
1025 .unwrap()
1026 }
1027
1028 pub(crate) fn ligature_components(&self) -> impl Iterator<Item = LigatureComponent> + '_ {
1029 self.iter().skip(3).filter_map(LigatureComponent::cast)
1030 }
1031}
1032
1033impl Gpos6 {
1034 pub(crate) fn base(&self) -> GlyphOrClass {
1035 self.iter()
1036 .filter(|t| !t.kind().is_trivia())
1037 .nth(2)
1038 .and_then(GlyphOrClass::cast)
1039 .unwrap()
1040 }
1041
1042 pub(crate) fn attachments(&self) -> impl Iterator<Item = AnchorMark> + '_ {
1043 self.iter().skip(3).filter_map(AnchorMark::cast)
1044 }
1045}
1046
1047impl Gpos8 {
1048 pub(crate) fn trailing_value_record(&self) -> Option<ValueRecord> {
1049 self.iter().skip(4).find_map(ValueRecord::cast)
1050 }
1051}
1052
1053impl GposIgnore {
1054 pub(crate) fn rules(&self) -> impl Iterator<Item = IgnoreRule> + '_ {
1055 self.iter().filter_map(IgnoreRule::cast)
1056 }
1057}
1058
1059impl LigatureComponent {
1060 pub(crate) fn attachments(&self) -> impl Iterator<Item = AnchorMark> + '_ {
1062 self.iter().filter_map(AnchorMark::cast)
1063 }
1064}
1065
1066impl AnchorMark {
1067 pub(crate) fn anchor(&self) -> Anchor {
1068 self.iter().find_map(Anchor::cast).unwrap()
1069 }
1070
1071 pub(crate) fn mark_class_name(&self) -> Option<GlyphClassName> {
1072 self.iter().find_map(GlyphClassName::cast)
1073 }
1074}
1075
1076impl ValueRecord {
1077 pub(crate) fn advance(&self) -> Option<Metric> {
1079 self.iter().next().and_then(Metric::cast)
1080 }
1081
1082 pub(crate) fn null(&self) -> Option<&Token> {
1083 self.iter()
1084 .take(3)
1085 .find(|t| t.kind() == Kind::NullKw)
1086 .and_then(NodeOrToken::as_token)
1087 }
1088
1089 pub(crate) fn named(&self) -> Option<&Token> {
1090 self.find_token(Kind::Ident)
1091 }
1092
1093 pub(crate) fn all_metrics(&self) -> impl Iterator<Item = Metric> + '_ {
1095 self.iter().filter_map(Metric::cast)
1096 }
1097
1098 pub(crate) fn placement(&self) -> Option<[Metric; 4]> {
1099 if self.iter().filter_map(Metric::cast).count() == 4 {
1100 let mut iter = self.iter().filter_map(Metric::cast);
1101 return Some([
1102 iter.next().unwrap(),
1103 iter.next().unwrap(),
1104 iter.next().unwrap(),
1105 iter.next().unwrap(),
1106 ]);
1107 }
1108 None
1109 }
1110
1111 pub(crate) fn device(&self) -> Option<[Device; 4]> {
1112 if self.iter().skip(4).any(|t| t.kind() == Kind::DeviceNode) {
1113 let mut iter = self.iter().filter_map(Device::cast);
1114 return Some([
1115 iter.next().unwrap(),
1116 iter.next().unwrap(),
1117 iter.next().unwrap(),
1118 iter.next().unwrap(),
1119 ]);
1120 }
1121 None
1122 }
1123}
1124
1125impl Device {
1126 fn null(&self) -> Option<&Token> {
1127 self.iter()
1128 .take(4)
1129 .find(|t| t.kind() == Kind::NullKw)
1130 .and_then(NodeOrToken::as_token)
1131 }
1132
1133 fn entries(&self) -> impl Iterator<Item = (Number, Number)> + '_ {
1134 let mut iter = self
1135 .iter()
1136 .filter(|i| i.kind() == Kind::Number || i.kind() == Kind::Comma);
1137 std::iter::from_fn(move || {
1138 let ppem = iter.next().and_then(Number::cast)?;
1139 let pixels = iter.next().and_then(Number::cast).unwrap();
1140 let _maybe_comma = iter.next();
1141 Some((ppem, pixels))
1142 })
1143 }
1144
1145 pub(crate) fn compile(&self) -> Option<write_fonts::tables::layout::Device> {
1146 if self.null().is_some() {
1147 return None;
1148 }
1149
1150 let mut entries = Vec::new();
1151 for (ppem, pix) in self.entries() {
1152 let ppem = ppem.parse_unsigned().expect("validated before now");
1153 let pix = pix.parse_signed();
1154 if let Some(prev) = entries.last().map(|(pp, _)| *pp) {
1156 for missing in (prev + 1)..ppem {
1157 entries.push((missing, 0));
1158 }
1159 }
1160 entries.push((ppem, pix));
1161 }
1162
1163 let first = entries.first().unwrap().0;
1164 let last = entries.last().unwrap().0;
1165 let values = entries
1166 .into_iter()
1167 .map(|(_, pix)| i8::try_from(pix).expect("validated before now"))
1168 .collect::<Vec<_>>();
1169
1170 Some(write_fonts::tables::layout::Device::new(
1171 first, last, &values,
1172 ))
1173 }
1174}
1175
1176impl Table {
1177 pub(crate) fn tag(&self) -> Tag {
1178 self.node()
1179 .unwrap()
1180 .iter_children()
1181 .find_map(Tag::cast)
1182 .unwrap()
1183 }
1184}
1185
1186impl BaseTable {
1187 pub(crate) fn horiz_base_tag_list(&self) -> Option<BaseTagList> {
1188 self.iter()
1189 .filter_map(BaseTagList::cast)
1190 .find(BaseTagList::is_horiz)
1191 }
1192
1193 pub(crate) fn vert_base_tag_list(&self) -> Option<BaseTagList> {
1194 self.iter()
1195 .filter_map(BaseTagList::cast)
1196 .find(|b| !b.is_horiz())
1197 }
1198
1199 pub(crate) fn horiz_base_script_record_list(&self) -> Option<BaseScriptList> {
1200 self.iter()
1201 .filter_map(BaseScriptList::cast)
1202 .find(BaseScriptList::is_horiz)
1203 }
1204
1205 pub(crate) fn vert_base_script_record_list(&self) -> Option<BaseScriptList> {
1206 self.iter()
1207 .filter_map(BaseScriptList::cast)
1208 .find(|b| !b.is_horiz())
1209 }
1210}
1211
1212impl BaseTagList {
1213 fn is_horiz(&self) -> bool {
1214 match self.iter().next().map(|t| t.kind()) {
1215 Some(Kind::HorizAxisBaseTagListKw) => true,
1216 Some(Kind::VertAxisBaseTagListKw) => false,
1217 other => panic!("unexpected token in BaseTagList {other:?}"),
1218 }
1219 }
1220
1221 pub(crate) fn tags(&self) -> impl Iterator<Item = Tag> + '_ {
1222 self.iter()
1223 .skip(1)
1224 .take_while(|t| t.kind() != Kind::Semi)
1225 .filter_map(Tag::cast)
1226 }
1227}
1228
1229impl BaseScriptList {
1230 fn is_horiz(&self) -> bool {
1231 match self.iter().next().map(|t| t.kind()) {
1232 Some(Kind::HorizAxisBaseScriptListKw) => true,
1233 Some(Kind::VertAxisBaseScriptListKw) => false,
1234 other => panic!("unexpected token in BaseScriptList {other:?}"),
1235 }
1236 }
1237
1238 pub(crate) fn script_records(&self) -> impl Iterator<Item = ScriptRecord> + '_ {
1239 self.iter()
1240 .skip(1)
1241 .take_while(|t| t.kind() != Kind::Semi)
1242 .filter_map(ScriptRecord::cast)
1243 }
1244}
1245
1246impl ScriptRecord {
1247 pub(crate) fn script(&self) -> Tag {
1248 self.iter().find_map(Tag::cast).unwrap()
1249 }
1250
1251 pub(crate) fn default_baseline(&self) -> Tag {
1252 self.iter().filter_map(Tag::cast).nth(1).unwrap()
1253 }
1254
1255 pub(crate) fn values(&self) -> impl Iterator<Item = Number> + '_ {
1256 self.iter().skip(2).filter_map(Number::cast)
1257 }
1258}
1259
1260impl HheaTable {
1261 pub(crate) fn metrics(&self) -> impl Iterator<Item = MetricRecord> + '_ {
1262 self.iter().filter_map(MetricRecord::cast)
1263 }
1264}
1265
1266impl VheaTable {
1267 pub(crate) fn metrics(&self) -> impl Iterator<Item = MetricRecord> + '_ {
1268 self.iter().filter_map(MetricRecord::cast)
1269 }
1270}
1271
1272impl VmtxTable {
1273 pub(crate) fn statements(&self) -> impl Iterator<Item = VmtxEntry> + '_ {
1274 self.iter().filter_map(VmtxEntry::cast)
1275 }
1276}
1277
1278impl VmtxEntry {
1279 pub(crate) fn keyword(&self) -> &Token {
1280 self.iter().next().and_then(NodeOrToken::as_token).unwrap()
1281 }
1282
1283 pub(crate) fn glyph(&self) -> Glyph {
1284 self.iter().find_map(Glyph::cast).unwrap()
1285 }
1286
1287 pub(crate) fn value(&self) -> Number {
1288 self.iter().find_map(Number::cast).unwrap()
1289 }
1290}
1291
1292impl MetricRecord {
1293 pub(crate) fn keyword(&self) -> &Token {
1294 self.iter().next().and_then(|t| t.as_token()).unwrap()
1295 }
1296
1297 pub(crate) fn metric(&self) -> Metric {
1298 self.iter().find_map(Metric::cast).unwrap()
1299 }
1300}
1301
1302impl Metric {
1303 pub(crate) fn parse_simple(&self) -> Option<i16> {
1305 match self {
1306 Metric::Scalar(num) => Some(num.parse_signed()),
1307 Metric::Variable(_) | Metric::GlyphsAppNumber(_) => None,
1308 }
1309 }
1310}
1311
1312impl VariableMetric {
1313 pub(crate) fn location_values(&self) -> impl Iterator<Item = LocationValue> + '_ {
1314 self.iter().filter_map(LocationValue::cast)
1315 }
1316}
1317
1318impl LocationValue {
1319 pub(crate) fn location(&self) -> LocationSpec {
1320 self.iter().find_map(LocationSpec::cast).unwrap()
1321 }
1322
1323 pub(crate) fn value(&self) -> Number {
1324 self.iter().find_map(Number::cast).unwrap()
1325 }
1326}
1327
1328impl LocationSpec {
1329 pub(crate) fn items(&self) -> impl Iterator<Item = LocationSpecItem> + '_ {
1330 self.iter().filter_map(LocationSpecItem::cast)
1331 }
1332}
1333
1334impl LocationSpecItem {
1335 pub(crate) fn axis_tag(&self) -> Tag {
1336 self.iter().find_map(Tag::cast).unwrap()
1337 }
1338
1339 pub(crate) fn value(&self) -> AxisLocation {
1340 self.iter().skip(2).find_map(AxisLocation::cast).unwrap()
1341 }
1342}
1343
1344impl AxisLocation {
1345 pub(crate) fn parse(&self) -> crate::compile::AxisLocation {
1346 use crate::compile::AxisLocation as Output;
1347 let value = self.value();
1348 match self.suffix() {
1349 Some(token) if token.text() == "n" => Output::Normalized(value.into()),
1350 Some(token) if token.text() == "d" => Output::Design(value.into()),
1351 Some(token) if token.text() == "u" => Output::User(value.into()),
1352 None => Output::User(value.into()),
1353 Some(_) => unreachable!("we only parse three suffixes"),
1354 }
1355 }
1356
1357 fn value(&self) -> f64 {
1358 let raw = self.iter().next().unwrap();
1359 Number::cast(raw)
1360 .map(|num| num.parse_signed() as f64)
1361 .or_else(|| Float::cast(raw).map(|num| num.parse()))
1362 .unwrap()
1363 }
1364
1365 fn suffix(&self) -> Option<NumberSuffix> {
1366 self.iter().find_map(NumberSuffix::cast)
1367 }
1368}
1369
1370impl Os2Table {
1371 pub(crate) fn statements(&self) -> impl Iterator<Item = Os2TableItem> + '_ {
1372 self.iter().filter_map(Os2TableItem::cast)
1373 }
1374}
1375
1376impl NumberRecord {
1377 pub(crate) fn keyword(&self) -> &Token {
1378 self.iter().next().and_then(|t| t.as_token()).unwrap()
1379 }
1380
1381 pub(crate) fn number(&self) -> Number {
1382 self.iter().find_map(Number::cast).unwrap()
1383 }
1384}
1385
1386impl VendorRecord {
1387 pub(crate) fn value(&self) -> &Token {
1388 self.find_token(Kind::String).unwrap()
1389 }
1390
1391 pub(crate) fn parse_tag(
1392 &self,
1393 ) -> Result<write_fonts::types::Tag, write_fonts::types::InvalidTag> {
1394 let raw = self.value();
1395 write_fonts::types::Tag::new_checked(raw.text.trim_matches('"').as_bytes())
1396 }
1397}
1398
1399impl Os2NumberList {
1400 pub(crate) fn keyword(&self) -> &Token {
1401 self.iter().next().and_then(|t| t.as_token()).unwrap()
1402 }
1403
1404 pub(crate) fn values(&self) -> impl Iterator<Item = Number> + '_ {
1405 self.iter().skip(1).filter_map(Number::cast)
1406 }
1407}
1408
1409impl Os2FamilyClass {
1410 pub(crate) fn value(&self) -> DecOctHex {
1411 self.iter().find_map(DecOctHex::cast).unwrap()
1412 }
1413}
1414
1415impl FeatureNames {
1416 pub(crate) fn keyword(&self) -> &Token {
1417 debug_assert_eq!(self.iter().next().unwrap().kind(), Kind::FeatureNamesKw);
1418 self.iter().next().and_then(|t| t.as_token()).unwrap()
1419 }
1420
1421 pub(crate) fn statements(&self) -> impl Iterator<Item = NameSpec> + '_ {
1422 self.iter().filter_map(NameSpec::cast)
1423 }
1424}
1425
1426impl CvParameters {
1427 pub(crate) fn keyword(&self) -> &Token {
1428 debug_assert_eq!(self.iter().next().unwrap().kind(), Kind::CvParametersKw);
1429 self.iter().next().and_then(|t| t.as_token()).unwrap()
1430 }
1431
1432 pub(crate) fn find_node(&self, kind: Kind) -> Option<CvParametersName> {
1433 self.iter()
1434 .filter_map(CvParametersName::cast)
1435 .find(|node| node.keyword().kind == kind)
1436 }
1437
1438 pub(crate) fn feat_ui_label_name(&self) -> Option<CvParametersName> {
1439 self.find_node(Kind::FeatUiLabelNameIdKw)
1440 }
1441
1442 pub(crate) fn feat_tooltip_text_name(&self) -> Option<CvParametersName> {
1443 self.find_node(Kind::FeatUiTooltipTextNameIdKw)
1444 }
1445
1446 pub(crate) fn sample_text_name(&self) -> Option<CvParametersName> {
1447 self.find_node(Kind::SampleTextNameIdKw)
1448 }
1449
1450 pub(crate) fn param_ui_label_name(&self) -> impl Iterator<Item = CvParametersName> + '_ {
1451 self.iter()
1452 .filter_map(CvParametersName::cast)
1453 .filter(|node| node.keyword().kind == Kind::ParamUiLabelNameIdKw)
1454 }
1455
1456 pub(crate) fn characters(&self) -> impl Iterator<Item = CvParametersChar> + '_ {
1457 self.iter().filter_map(CvParametersChar::cast)
1458 }
1459}
1460
1461impl CvParametersName {
1462 pub(crate) fn keyword(&self) -> &Token {
1463 self.iter().next().and_then(|t| t.as_token()).unwrap()
1464 }
1465
1466 pub(crate) fn statements(&self) -> impl Iterator<Item = NameSpec> + '_ {
1467 self.iter().filter_map(NameSpec::cast)
1468 }
1469}
1470
1471impl CvParametersChar {
1472 pub(crate) fn value(&self) -> DecOctHex {
1473 self.iter().find_map(DecOctHex::cast).unwrap()
1474 }
1475}
1476
1477impl NameTable {
1478 pub(crate) fn statements(&self) -> impl Iterator<Item = NameRecord> + '_ {
1479 self.iter().filter_map(NameRecord::cast)
1480 }
1481}
1482
1483impl NameRecord {
1484 pub(crate) fn name_id(&self) -> DecOctHex {
1485 self.iter().find_map(DecOctHex::cast).unwrap()
1486 }
1487
1488 pub(crate) fn entry(&self) -> NameSpec {
1489 self.iter().find_map(NameSpec::cast).unwrap()
1490 }
1491}
1492
1493impl NameSpec {
1494 pub(crate) fn platform_id(&self) -> Option<DecOctHex> {
1495 self.iter().find_map(DecOctHex::cast)
1496 }
1497
1498 pub(crate) fn platform_and_language_ids(&self) -> Option<(DecOctHex, DecOctHex)> {
1499 let mut iter = self.iter().filter_map(DecOctHex::cast).skip(1);
1500 if let Some(platform) = iter.next() {
1501 let language = iter.next().unwrap();
1502 Some((platform, language))
1503 } else {
1504 None
1505 }
1506 }
1507
1508 pub(crate) fn string_token(&self) -> &Token {
1509 self.find_token(Kind::String).unwrap()
1511 }
1512
1513 pub(crate) fn string(&self) -> &str {
1514 let s = self.string_token().as_str();
1516 &s[1..s.len() - 1]
1517 }
1518}
1519
1520impl DecOctHex {
1521 fn parse_raw(&self) -> Result<u32, String> {
1522 match self {
1523 DecOctHex::Decimal(num) => num.text().parse::<u32>().map_err(|e| e.to_string()),
1524 DecOctHex::Octal(num) => u32::from_str_radix(num.text(), 8).map_err(|e| e.to_string()),
1525 DecOctHex::Hex(num) => u32::from_str_radix(num.text().trim_start_matches("0x"), 16)
1526 .map_err(|e| e.to_string()),
1527 }
1528 }
1529
1530 pub(crate) fn parse(&self) -> Result<u16, String> {
1531 self.parse_raw()
1532 .and_then(|x| u16::try_from(x).map_err(|e| e.to_string()))
1533 }
1534
1535 pub(crate) fn parse_char(&self) -> Result<char, String> {
1536 self.parse_raw().and_then(|int| {
1537 char::from_u32(int).ok_or_else(|| format!("{int} is not a unicode codepoint"))
1538 })
1539 }
1540}
1541
1542impl GdefTable {
1543 pub(crate) fn statements(&self) -> impl Iterator<Item = GdefTableItem> + '_ {
1544 self.iter().filter_map(GdefTableItem::cast)
1545 }
1546}
1547
1548impl GdefClassDef {
1549 fn nth_item(&self, n: usize) -> Option<GlyphClass> {
1550 assert!(n < 4);
1551 self.iter()
1552 .filter(|t| t.kind() == Kind::GdefClassDefEntryNode)
1553 .nth(n)
1554 .and_then(GdefClassDefEntry::cast)
1555 .expect("validated")
1556 .iter()
1557 .find_map(GlyphClass::cast)
1558 }
1559
1560 pub(crate) fn base_glyphs(&self) -> Option<GlyphClass> {
1561 self.nth_item(0)
1562 }
1563
1564 pub(crate) fn ligature_glyphs(&self) -> Option<GlyphClass> {
1565 self.nth_item(1)
1566 }
1567
1568 pub(crate) fn mark_glyphs(&self) -> Option<GlyphClass> {
1569 self.nth_item(2)
1570 }
1571
1572 pub(crate) fn component_glyphs(&self) -> Option<GlyphClass> {
1573 self.nth_item(3)
1574 }
1575}
1576
1577impl GdefAttach {
1578 pub(crate) fn target(&self) -> GlyphOrClass {
1579 self.iter().find_map(GlyphOrClass::cast).unwrap()
1580 }
1581
1582 pub(crate) fn indices(&self) -> impl Iterator<Item = Number> + '_ {
1584 self.iter().filter_map(Number::cast)
1585 }
1586}
1587
1588impl GdefLigatureCaret {
1589 fn by_pos(&self) -> bool {
1590 match self.iter().next().map(|t| t.kind()) {
1591 Some(Kind::LigatureCaretByPosKw) => true,
1592 Some(Kind::LigatureCaretByIndexKw) => false,
1593 other => panic!("unexpected token in ligaturecaret {other:?}"),
1594 }
1595 }
1596
1597 pub(crate) fn target(&self) -> GlyphOrClass {
1598 self.iter().find_map(GlyphOrClass::cast).unwrap()
1599 }
1600
1601 pub(crate) fn values(&self) -> LigatureCaretValue<'_> {
1602 if self.by_pos() {
1603 LigatureCaretValue::Pos(LigatureCaretIter(self))
1604 } else {
1605 LigatureCaretValue::Index(LigatureCaretIter(self))
1606 }
1607 }
1608}
1609
1610pub(crate) struct LigatureCaretIter<'a>(&'a GdefLigatureCaret);
1613
1614impl LigatureCaretIter<'_> {
1615 pub(crate) fn values(&self) -> impl Iterator<Item = Number> + '_ {
1616 self.0.iter().filter_map(Number::cast)
1617 }
1618}
1619
1620pub(crate) enum LigatureCaretValue<'a> {
1621 Pos(LigatureCaretIter<'a>),
1622 Index(LigatureCaretIter<'a>),
1623}
1624
1625impl HeadTable {
1626 pub(crate) fn statements(&self) -> impl Iterator<Item = HeadFontRevision> + '_ {
1627 self.iter().filter_map(HeadFontRevision::cast)
1628 }
1629}
1630
1631impl HeadFontRevision {
1632 pub(crate) fn value(&self) -> Float {
1633 self.iter().find_map(Float::cast).unwrap()
1634 }
1635}
1636
1637impl StatTable {
1638 pub(crate) fn tag(&self) -> Tag {
1639 self.iter().find_map(Tag::cast).unwrap()
1640 }
1641
1642 pub(crate) fn statements(&self) -> impl Iterator<Item = StatTableItem> + '_ {
1643 self.iter().filter_map(StatTableItem::cast)
1644 }
1645}
1646
1647impl StatElidedFallbackName {
1648 pub(crate) fn elided_fallback_name_id(&self) -> Option<Number> {
1649 self.iter()
1650 .take_while(|t| t.kind() != Kind::NameKw)
1651 .find_map(Number::cast)
1652 }
1653
1654 pub(crate) fn names(&self) -> impl Iterator<Item = NameSpec> + '_ {
1655 self.iter().filter_map(NameSpec::cast)
1656 }
1657}
1658
1659impl StatDesignAxis {
1660 pub(crate) fn tag(&self) -> Tag {
1661 self.iter().find_map(Tag::cast).unwrap()
1662 }
1663
1664 pub(crate) fn ordering(&self) -> Number {
1665 self.iter()
1666 .take_while(|t| t.kind() != Kind::LBrace)
1667 .find_map(Number::cast)
1668 .unwrap()
1669 }
1670
1671 pub(crate) fn names(&self) -> impl Iterator<Item = NameSpec> + '_ {
1672 self.iter()
1673 .skip_while(|t| t.kind() != Kind::LBrace)
1674 .filter_map(NameSpec::cast)
1675 }
1676}
1677
1678impl StatAxisValue {
1679 pub(crate) fn statements(&self) -> impl Iterator<Item = StatAxisValueItem> + '_ {
1680 self.iter().skip(2).filter_map(StatAxisValueItem::cast)
1681 }
1682}
1683
1684impl StatAxisFlag {
1685 pub(crate) fn bits(&self) -> impl Iterator<Item = u16> + '_ {
1687 self.iter()
1688 .skip(1)
1689 .take_while(|t| t.kind() != Kind::Semi)
1690 .filter_map(|t| match t.kind() {
1691 Kind::OlderSiblingFontAttributeKw => Some(0x01),
1692 Kind::ElidableAxisValueNameKw => Some(0x02),
1693 t if t.is_trivia() => None,
1694 other => panic!("parser error '{other}'"),
1695 })
1696 }
1697}
1698
1699impl StatAxisLocation {
1700 pub(crate) fn tag(&self) -> Tag {
1701 self.iter().find_map(Tag::cast).unwrap()
1702 }
1703
1704 pub(crate) fn value(&self) -> StatLocationValue {
1705 let mut iter = self.iter().filter_map(FloatLike::cast);
1706 let first = iter.next().unwrap();
1707 let second = match iter.next() {
1708 Some(second) => second,
1709 None => return StatLocationValue::Value(first),
1710 };
1711 match iter.next() {
1712 Some(third) => StatLocationValue::MinMax {
1713 nominal: first,
1714 min: second,
1715 max: third,
1716 },
1717 None => StatLocationValue::Linked {
1718 value: first,
1719 linked: second,
1720 },
1721 }
1722 }
1723}
1724
1725pub(crate) enum StatLocationValue {
1726 Value(FloatLike),
1727 MinMax {
1728 nominal: FloatLike,
1729 min: FloatLike,
1730 max: FloatLike,
1731 },
1732 Linked {
1733 value: FloatLike,
1734 linked: FloatLike,
1735 },
1736}
1737
1738impl SizeMenuName {
1739 pub(crate) fn spec(&self) -> NameSpec {
1740 self.iter().find_map(NameSpec::cast).unwrap()
1741 }
1742}
1743
1744impl Parameters {
1745 pub(crate) fn design_size(&self) -> FloatLike {
1746 self.iter().find_map(FloatLike::cast).unwrap()
1747 }
1748
1749 pub(crate) fn subfamily(&self) -> Number {
1750 self.iter()
1751 .filter(|t| t.kind() == Kind::Number || t.kind() == Kind::Float)
1752 .nth(1)
1753 .and_then(Number::cast)
1754 .unwrap()
1755 }
1756
1757 pub(crate) fn range_start(&self) -> Option<FloatLike> {
1758 self.iter().filter_map(FloatLike::cast).nth(2)
1759 }
1760
1761 pub(crate) fn range_end(&self) -> Option<FloatLike> {
1762 self.iter().filter_map(FloatLike::cast).nth(3)
1763 }
1764}
1765
1766impl FeatureRef {
1767 pub(crate) fn keyword(&self) -> &Token {
1768 self.find_token(Kind::FeatureKw).unwrap()
1769 }
1770
1771 pub(crate) fn feature(&self) -> Tag {
1772 self.iter().find_map(Tag::cast).unwrap()
1773 }
1774}
1775
1776impl GlyphsAppNumber {
1777 pub(crate) fn value(&self) -> GlyphsAppNumberValue {
1778 self.iter().find_map(GlyphsAppNumberValue::cast).unwrap()
1779 }
1780}
1781
1782impl GlyphsAppNumberExpr {
1783 pub(crate) fn items(&self) -> impl Iterator<Item = GlyphsAppExprItem> + '_ {
1784 self.iter().filter_map(GlyphsAppExprItem::cast)
1785 }
1786}