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