Skip to main content

device_driver_parser/
lib.rs

1use std::{borrow::Cow, fmt::Display, num::NonZeroU32, sync::LazyLock};
2
3use chumsky::{
4    IterParser, Parser,
5    error::Rich,
6    extra,
7    input::{Input, MappedInput},
8    inspector::Inspector,
9    prelude::{choice, just, recursive},
10    select,
11};
12use device_driver_common::{
13    interner::{Istr, StrExt},
14    span::{Span, SpanExt, Spanned},
15    specifiers::{Access, AddressMode, BaseType, ByteOrder, Integer},
16};
17use device_driver_diagnostics::{Diagnostics, errors::ParsingError};
18use device_driver_lexer::{
19    Token, TokenModifier, TokenType,
20    semantic_token_object::{SemanticToken, SemanticTokenObject},
21};
22
23use crate::parse_num::{ParseIntRadix, ParseIntRadixError, ParseIntRadixErrorKind, parse_num};
24
25#[cfg(feature = "gen-docs")]
26pub mod gen_docs;
27mod parse_num;
28
29#[derive(Default)]
30pub struct AstArena {
31    nodes: Vec<Node>,
32}
33
34impl AstArena {
35    pub fn alloc_node(&mut self, node: Node) -> NodeId {
36        let id = NodeId(self.nodes.len());
37        self.nodes.push(node);
38        id
39    }
40}
41
42impl<'src, I: Input<'src>> Inspector<'src, I> for AstArena {
43    type Checkpoint = AstArenaCheckpoint;
44
45    fn on_token(&mut self, _token: &I::Token) {}
46
47    fn on_save<'parse>(
48        &self,
49        _cursor: &chumsky::input::Cursor<'src, 'parse, I>,
50    ) -> Self::Checkpoint {
51        AstArenaCheckpoint {
52            node_count: self.nodes.len(),
53        }
54    }
55
56    fn on_rewind<'parse>(
57        &mut self,
58        marker: &chumsky::input::Checkpoint<'src, 'parse, I, Self::Checkpoint>,
59    ) {
60        // undo all the pushes that happened since the checkpoint
61        self.nodes.truncate(marker.inspector().node_count);
62    }
63}
64
65#[derive(Debug, Clone, Copy)]
66pub struct AstArenaCheckpoint {
67    node_count: usize,
68}
69
70pub fn parse(tokens: &[Spanned<Token>], diagnostics: &mut Diagnostics) -> Ast {
71    let mut state = AstArena { nodes: Vec::new() };
72
73    let (ast, parse_errs) = node()
74        .map_with(|ast, e| (ast, e.span()))
75        .parse_with_state(
76            tokens.map(
77                tokens
78                    .last()
79                    .map(|t| Span::from(t.span.end..t.span.end))
80                    .unwrap_or_default(),
81                |token| (&token.value, &token.span),
82            ),
83            &mut state,
84        )
85        .into_output_errors();
86
87    for error in parse_errs {
88        diagnostics.add(ParsingError {
89            reason: error.to_string(),
90            span: *error.span(),
91        });
92    }
93
94    Ast::new(
95        ast.map(|(ast, _)| ast),
96        state,
97        ast.as_ref().map(|(_, span)| *span).unwrap_or_default(),
98    )
99}
100
101// Don't forget to update the book when parsers are added, changed or removed!
102#[derive(Debug)]
103pub struct Ast {
104    pub root_node: Option<NodeId>,
105    nodes: Vec<Node>,
106    pub span: Span,
107}
108
109impl Ast {
110    pub fn new(root_node: Option<NodeId>, arena: AstArena, span: Span) -> Self {
111        Self {
112            root_node,
113            nodes: arena.nodes,
114            span,
115        }
116    }
117
118    pub fn node(&self, id: NodeId) -> &Node {
119        &self.nodes[id.0]
120    }
121
122    pub fn node_mut(&mut self, id: NodeId) -> &mut Node {
123        &mut self.nodes[id.0]
124    }
125
126    pub fn nodes(&self) -> &[Node] {
127        &self.nodes
128    }
129
130    pub fn nodes_mut(&mut self) -> &mut [Node] {
131        &mut self.nodes
132    }
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq)]
136pub struct NodeId(usize);
137
138#[derive(Debug, Clone)]
139pub struct Node {
140    pub doc_comments: Vec<Spanned<Istr>>,
141    pub node_type: Ident,
142    pub name: Ident,
143    pub repeat: Option<Spanned<Repeat>>,
144    pub type_specifier: Option<Spanned<TypeSpecifier>>,
145    pub short_properties: Vec<Spanned<Expression>>,
146    pub properties: Vec<Spanned<Property>>,
147    pub sub_nodes: Vec<NodeId>,
148    pub body_span: Option<Span>,
149    /// Span of the whole node including docs.
150    /// Don't want docs? Use [Self::non_docs_span()]
151    pub span: Span,
152}
153
154impl Node {
155    /// Get the span of the node, excluding docs
156    pub fn non_docs_span(&self) -> Span {
157        self.span.start_from(self.node_type.span)
158    }
159
160    pub fn to_string_formatted(&self, ast: &Ast) -> String {
161        let mut buf = String::new();
162        self.fmt_formatted(&mut buf, ast, 0).unwrap();
163        buf
164    }
165
166    pub fn fmt_formatted(
167        &self,
168        f: &mut impl std::fmt::Write,
169        ast: &Ast,
170        indentation_level: usize,
171    ) -> std::fmt::Result {
172        let indentation = format!("{:width$}", "", width = indentation_level * 4);
173
174        for doc_comment in &self.doc_comments {
175            writeln!(
176                f,
177                "{indentation}///{}{doc_comment}",
178                if doc_comment.starts_with(" ") {
179                    ""
180                } else {
181                    " "
182                }
183            )?;
184        }
185        write!(f, "{indentation}{} {}", self.node_type.val, self.name.val)?;
186
187        if let Some(repeat) = self.repeat {
188            write!(f, "[{} stride {}]", repeat.source, repeat.stride)?;
189        }
190
191        for expression in self.short_properties.iter() {
192            write!(f, " {}", expression.print_formatted(ast))?;
193        }
194
195        if let Some(type_specifier) = self.type_specifier.as_ref() {
196            write!(f, " -> {}", type_specifier.base_type)?;
197
198            if let Some(conversion) = type_specifier.conversion.as_ref() {
199                write!(f, " as")?;
200                if type_specifier.use_try {
201                    write!(f, " try")?;
202                }
203
204                match conversion {
205                    TypeConversion::Reference(ident) => write!(f, " {}", ident.val)?,
206                    TypeConversion::Subnode(node) => {
207                        let node = ast.node(*node);
208                        if node.doc_comments.is_empty() {
209                            for (i, line) in node.to_string_formatted(ast).lines().enumerate() {
210                                if i == 0 {
211                                    write!(f, " {line}")?;
212                                } else {
213                                    write!(f, "\n{indentation}{line}")?;
214                                }
215                            }
216                        } else {
217                            node.fmt_formatted(f, ast, indentation_level + 1)?;
218                        }
219                    }
220                }
221            }
222        }
223
224        if !self.sub_nodes.is_empty() || !self.properties.is_empty() {
225            writeln!(f, " {{")?;
226
227            for property in self.properties.iter() {
228                for doc_comment in property.doc_comments.iter() {
229                    writeln!(
230                        f,
231                        "{indentation}    ///{}{}",
232                        if doc_comment.starts_with(" ") {
233                            ""
234                        } else {
235                            " "
236                        },
237                        doc_comment
238                    )?;
239                }
240
241                write!(f, "{indentation}    {}:", property.name.val)?;
242
243                let expression = property.expression.print_formatted(ast);
244
245                if expression.starts_with("///") {
246                    for line in expression.lines() {
247                        write!(f, "\n{indentation}        {line}")?;
248                    }
249                } else {
250                    for (i, line) in expression.lines().enumerate() {
251                        if i == 0 {
252                            write!(f, " {line}")?;
253                        } else {
254                            write!(f, "\n{indentation}    {line}")?;
255                        }
256                    }
257                }
258
259                writeln!(f, ",")?;
260            }
261
262            if !self.properties.is_empty() && !self.sub_nodes.is_empty() {
263                writeln!(f, "{indentation}",)?;
264            }
265
266            for node in self.sub_nodes.iter() {
267                let node = ast.node(*node);
268                node.fmt_formatted(f, ast, indentation_level + 1)?;
269                writeln!(f, ",")?;
270            }
271
272            write!(f, "{indentation}}}")?;
273        }
274
275        Ok(())
276    }
277}
278
279impl SemanticTokenObject for Node {
280    type Context = Ast;
281
282    fn to_tokens_in(&self, ctx: &Self::Context, tokens: &mut Vec<SemanticToken<'_>>) {
283        tokens.extend(self.doc_comments.iter().map(|doc_comment| {
284            Token::DocCommentLine(doc_comment.as_str())
285                .with_semantics(TokenType::Comment, &[TokenModifier::Documentation])
286        }));
287        tokens.push(
288            Token::Ident(self.node_type.val.as_str()).with_semantics(TokenType::Keyword, &[]),
289        );
290        tokens.push(Token::Ident(self.name.val.as_str()).with_semantics(
291            TokenType::Type,
292            &[TokenModifier::Declaration, TokenModifier::Definition],
293        ));
294
295        if let Some(repeat) = self.repeat.as_ref() {
296            repeat.to_tokens_in(&(), tokens);
297        }
298
299        for short_property in self.short_properties.iter() {
300            short_property.to_tokens_in(ctx, tokens);
301        }
302
303        if let Some(type_specifier) = self.type_specifier.as_ref() {
304            type_specifier.to_tokens_in(ctx, tokens);
305        }
306
307        if self.properties.len() + self.sub_nodes.len() > 0 {
308            tokens.push(Token::CurlyOpen.without_semantics());
309
310            for property in self.properties.iter() {
311                property.to_tokens_in(ctx, tokens);
312                tokens.push(Token::Comma.without_semantics());
313            }
314
315            for sub_node in self.sub_nodes.iter() {
316                ctx.node(*sub_node).to_tokens_in(ctx, tokens);
317                tokens.push(Token::Comma.without_semantics());
318            }
319
320            tokens.push(Token::CurlyClose.without_semantics());
321        }
322    }
323}
324
325#[derive(Debug, Clone)]
326pub struct TypeSpecifier {
327    pub base_type: Spanned<BaseType>,
328    pub use_try: bool,
329    pub conversion: Option<TypeConversion>,
330}
331
332impl SemanticTokenObject for TypeSpecifier {
333    type Context = Ast;
334
335    fn to_tokens_in(&self, ctx: &Self::Context, tokens: &mut Vec<SemanticToken<'_>>) {
336        tokens.push(Token::Arrow.without_semantics());
337        self.base_type.to_tokens_in(&(), tokens);
338        if let Some(conversion) = self.conversion.as_ref() {
339            tokens.push(Token::As.with_semantics(TokenType::Keyword, &[TokenModifier::Expression]));
340            if self.use_try {
341                tokens.push(
342                    Token::Try.with_semantics(TokenType::Keyword, &[TokenModifier::Expression]),
343                );
344            }
345            conversion.to_tokens_in(ctx, tokens);
346        }
347    }
348}
349
350#[derive(Debug, Clone)]
351pub enum TypeConversion {
352    Reference(Ident),
353    Subnode(NodeId),
354}
355
356impl TypeConversion {
357    pub fn as_subnode(&self) -> Option<NodeId> {
358        if let Self::Subnode(v) = self {
359            Some(*v)
360        } else {
361            None
362        }
363    }
364}
365
366impl SemanticTokenObject for TypeConversion {
367    type Context = Ast;
368
369    fn to_tokens_in(&self, ctx: &Self::Context, tokens: &mut Vec<SemanticToken<'_>>) {
370        match self {
371            TypeConversion::Reference(ident) => {
372                tokens.push(Token::Ident(ident.val.as_str()).with_semantics(TokenType::Type, &[]))
373            }
374            TypeConversion::Subnode(node) => ctx.node(*node).to_tokens_in(ctx, tokens),
375        }
376    }
377}
378
379#[derive(Debug, Clone)]
380pub struct Property {
381    pub doc_comments: Vec<Spanned<Istr>>,
382    pub name: Ident,
383    pub expression: Spanned<Expression>,
384}
385
386impl SemanticTokenObject for Property {
387    type Context = Ast;
388
389    fn to_tokens_in(&self, ctx: &Self::Context, tokens: &mut Vec<SemanticToken<'_>>) {
390        tokens.extend(self.doc_comments.iter().map(|istr| {
391            Token::DocCommentLine(istr.as_str())
392                .with_semantics(TokenType::Comment, &[TokenModifier::Documentation])
393        }));
394        tokens.push(Token::Ident(self.name.val.as_str()).with_semantics(TokenType::Property, &[]));
395
396        tokens.push(Token::Colon.without_semantics());
397        self.expression.to_tokens_in(ctx, tokens);
398    }
399}
400
401#[derive(Debug, Clone)]
402pub enum Expression {
403    AddressRange { end: i128, start: i128 },
404    ByteArray(Vec<u8>),
405    BaseType(BaseType),
406    Integer(Integer),
407    Allow,
408    Number(i128),
409    DefaultNumber(Option<i128>),
410    CatchAllNumber(Option<i128>),
411    String(Istr),
412    Access(Access),
413    ByteOrder(ByteOrder),
414    TypeReference(Ident),
415    SubNode(NodeId),
416    Auto,
417    AddressMode(AddressMode),
418}
419
420impl Expression {
421    pub fn as_range(&self) -> Option<(i128, i128)> {
422        if let Self::AddressRange { end, start } = self {
423            Some((*end, *start))
424        } else {
425            None
426        }
427    }
428
429    pub fn as_byte_order(&self) -> Option<ByteOrder> {
430        if let Self::ByteOrder(v) = self {
431            Some(*v)
432        } else {
433            None
434        }
435    }
436
437    pub fn as_access(&self) -> Option<Access> {
438        if let Self::Access(v) = self {
439            Some(*v)
440        } else {
441            None
442        }
443    }
444
445    pub fn as_integer(&self) -> Option<Integer> {
446        if let Self::Integer(v) = self {
447            Some(*v)
448        } else {
449            None
450        }
451    }
452
453    pub fn as_unsigned_integer(&self) -> Option<Integer> {
454        if let Self::Integer(v) = self {
455            Some(*v)
456        } else {
457            None
458        }
459    }
460
461    pub fn as_number(&self) -> Option<i128> {
462        if let Self::Number(v) = self {
463            Some(*v)
464        } else {
465            None
466        }
467    }
468
469    pub fn as_string(&self) -> Option<Istr> {
470        if let Self::String(v) = self {
471            Some(*v)
472        } else {
473            None
474        }
475    }
476
477    pub fn as_address_mode(&self) -> Option<AddressMode> {
478        if let Self::AddressMode(v) = self {
479            Some(*v)
480        } else {
481            None
482        }
483    }
484
485    pub fn as_sub_node(&self) -> Option<NodeId> {
486        if let Self::SubNode(v) = self {
487            Some(*v)
488        } else {
489            None
490        }
491    }
492
493    pub fn print_formatted(&self, ast: &Ast) -> Cow<'static, str> {
494        match self {
495            Expression::AddressRange { end, start } => format!("{end}:{start}").into(),
496            Expression::ByteArray(items) => format!("{items:?}").into(),
497            Expression::BaseType(base_type) => base_type.to_string().into(),
498            Expression::Integer(integer) => integer.to_string().into(),
499            Expression::Allow => "allow".into(),
500            Expression::Number(num) => num.to_string().into(),
501            Expression::DefaultNumber(Some(num)) => format!("default {num}").into(),
502            Expression::DefaultNumber(None) => "default _".into(),
503            Expression::CatchAllNumber(Some(num)) => format!("catch-all {num}").into(),
504            Expression::CatchAllNumber(None) => "catch-all _".into(),
505            Expression::String(val) => format!("\"{val}\"").into(),
506            Expression::Access(val) => val.to_string().into(),
507            Expression::ByteOrder(val) => val.to_string().into(),
508            Expression::TypeReference(ident) => ident.val.to_string().into(),
509            Expression::SubNode(val) => ast.node(*val).to_string_formatted(ast).into(),
510            Expression::Auto => "_".into(),
511            Expression::AddressMode(val) => val.to_string().into(),
512        }
513    }
514}
515
516impl Display for Expression {
517    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
518        match self {
519            Expression::AddressRange { .. } => write!(f, "range"),
520            Expression::ByteArray(_) => write!(f, "[bytes]"),
521            Expression::BaseType(_) => write!(f, "base type"),
522            Expression::Integer(_) => write!(f, "integer type"),
523            Expression::Allow => write!(f, "allow"),
524            Expression::Number(_) => write!(f, "number"),
525            Expression::DefaultNumber(None) => write!(f, "default auto"),
526            Expression::CatchAllNumber(None) => write!(f, "catch-all auto"),
527            Expression::DefaultNumber(Some(_)) => write!(f, "default number"),
528            Expression::CatchAllNumber(Some(_)) => write!(f, "catch-all number"),
529            Expression::String(_) => write!(f, "string"),
530            Expression::Access(_) => write!(f, "access specifier"),
531            Expression::ByteOrder(_) => write!(f, "byte order"),
532            Expression::TypeReference(_) => write!(f, "type reference"),
533            Expression::SubNode(_) => write!(f, "sub node"),
534            Expression::Auto => write!(f, "auto"),
535            Expression::AddressMode(_) => write!(f, "address mode"),
536        }
537    }
538}
539
540impl SemanticTokenObject for Expression {
541    type Context = Ast;
542
543    fn to_tokens_in(&self, ctx: &Self::Context, tokens: &mut Vec<SemanticToken<'_>>) {
544        match self {
545            Expression::AddressRange { end, start } => {
546                tokens.push(
547                    Token::Num(end.to_string().intern().as_str())
548                        .with_semantics(TokenType::Number, &[]),
549                );
550                tokens.push(Token::Colon.without_semantics());
551                tokens.push(
552                    Token::Num(start.to_string().intern().as_str())
553                        .with_semantics(TokenType::Number, &[]),
554                );
555            }
556            Expression::ByteArray(bytes) => {
557                tokens.push(Token::BracketOpen.without_semantics());
558                for (i, byte) in bytes.iter().enumerate() {
559                    if i != 0 {
560                        tokens.push(Token::Comma.without_semantics());
561                    }
562                    tokens.push(
563                        Token::Num(byte.to_string().intern().as_str())
564                            .with_semantics(TokenType::Number, &[]),
565                    );
566                }
567                tokens.push(Token::BracketClose.without_semantics());
568            }
569            Expression::BaseType(base_type) => base_type.to_tokens_in(&(), tokens),
570            Expression::Integer(integer) => integer.to_tokens_in(&(), tokens),
571            Expression::Allow => tokens.push(Token::Allow.with_semantics(TokenType::Keyword, &[])),
572            Expression::Number(num) => tokens.push(
573                Token::Num(num.to_string().intern().as_str())
574                    .with_semantics(TokenType::Number, &[]),
575            ),
576            Expression::DefaultNumber(num) => {
577                tokens.push(Token::Default.with_semantics(TokenType::Keyword, &[]));
578                match num {
579                    Some(num) => {
580                        tokens.push(
581                            Token::Num(num.to_string().intern().as_str())
582                                .with_semantics(TokenType::Number, &[]),
583                        );
584                    }
585                    None => {
586                        tokens.push(Token::Underscore.with_semantics(TokenType::Operator, &[]));
587                    }
588                }
589            }
590            Expression::CatchAllNumber(num) => {
591                tokens.push(Token::CatchAll.with_semantics(TokenType::Keyword, &[]));
592                match num {
593                    Some(num) => {
594                        tokens.push(
595                            Token::Num(num.to_string().intern().as_str())
596                                .with_semantics(TokenType::Number, &[]),
597                        );
598                    }
599                    None => {
600                        tokens.push(Token::Underscore.with_semantics(TokenType::Operator, &[]));
601                    }
602                }
603            }
604            Expression::String(istr) => {
605                tokens.push(Token::String(istr.as_str()).with_semantics(TokenType::String, &[]));
606            }
607            Expression::Access(access) => access.to_tokens_in(&(), tokens),
608            Expression::ByteOrder(byte_order) => byte_order.to_tokens_in(&(), tokens),
609            Expression::TypeReference(ident) => {
610                tokens.push(Token::Ident(ident.val.as_str()).with_semantics(TokenType::Type, &[]))
611            }
612            Expression::SubNode(node) => ctx.node(*node).to_tokens_in(ctx, tokens),
613            Expression::Auto => {
614                tokens.push(Token::Underscore.with_semantics(TokenType::Operator, &[]));
615            }
616            Expression::AddressMode(address_mode) => address_mode.to_tokens_in(&(), tokens),
617        }
618    }
619}
620
621#[derive(Debug, Clone, Copy, Default)]
622pub struct Repeat {
623    pub source: Spanned<RepeatSource>,
624    pub stride: Spanned<i32>,
625}
626
627impl SemanticTokenObject for Repeat {
628    type Context = ();
629
630    fn to_tokens_in(&self, ctx: &Self::Context, tokens: &mut Vec<SemanticToken<'_>>) {
631        tokens.push(Token::BracketOpen.without_semantics());
632        self.source.to_tokens_in(ctx, tokens);
633        tokens.push(Token::Stride.with_semantics(TokenType::Keyword, &[TokenModifier::Expression]));
634        tokens.push(
635            Token::Num(self.stride.to_string().intern().as_str())
636                .with_semantics(TokenType::Number, &[]),
637        );
638        tokens.push(Token::BracketClose.without_semantics());
639    }
640}
641
642#[derive(Debug, Clone, Copy)]
643pub enum RepeatSource {
644    Count(NonZeroU32),
645    Enum(Ident),
646}
647
648impl Default for RepeatSource {
649    fn default() -> Self {
650        Self::Count(1.try_into().unwrap())
651    }
652}
653
654impl Display for RepeatSource {
655    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
656        match self {
657            RepeatSource::Count(non_zero) => write!(f, "{non_zero}"),
658            RepeatSource::Enum(ident) => write!(f, "{}", ident.val),
659        }
660    }
661}
662
663impl SemanticTokenObject for RepeatSource {
664    type Context = ();
665
666    fn to_tokens_in(&self, _ctx: &Self::Context, tokens: &mut Vec<SemanticToken<'_>>) {
667        match self {
668            RepeatSource::Count(non_zero) => tokens.push(
669                Token::Num(non_zero.get().to_string().intern().as_str())
670                    .with_semantics(TokenType::Number, &[]),
671            ),
672            RepeatSource::Enum(ident) => {
673                tokens.push(Token::Ident(ident.val.as_str()).with_semantics(TokenType::Type, &[]))
674            }
675        }
676    }
677}
678
679#[derive(Debug, Clone, Copy)]
680pub struct Ident {
681    pub val: Istr,
682    pub span: Span,
683}
684
685impl Ident {
686    pub const fn new(val: Istr, span: Span) -> Self {
687        Self { val, span }
688    }
689
690    pub const fn new_no_span(val: Istr) -> Self {
691        Self {
692            val,
693            span: Span::empty(),
694        }
695    }
696
697    pub fn new_auto(span: Span) -> Self {
698        Self {
699            val: "_".intern(),
700            span,
701        }
702    }
703
704    /// Returns true if the identifier was specified using an underscore token
705    pub fn is_auto(&self) -> bool {
706        static UNDERSCORE: LazyLock<Istr> = LazyLock::new(|| "_".intern());
707        self.val == *UNDERSCORE
708    }
709}
710
711fn try_num<'tokens, 'src: 'tokens, I: ParseIntRadix>(
712    num_str: &'src str,
713    span: Span,
714) -> Result<I, RichErr<'tokens, 'src>> {
715    match parse_num::<I>(num_str) {
716        Ok(num) => Ok(num),
717        Err(ParseIntRadixError {
718            source,
719            kind,
720            target_bits,
721            target_signed,
722        }) => match kind {
723            ParseIntRadixErrorKind::Overflow => Err(Rich::custom(
724                span,
725                format!(
726                    "number `{source}` is parsed as a {}{target_bits}, but overflows.",
727                    if target_signed { 'i' } else { 'u' }
728                ),
729            )),
730            ParseIntRadixErrorKind::Underflow => Err(Rich::custom(
731                span,
732                format!(
733                    "number `{source}` is parsed as a {}{target_bits}, but underflows.",
734                    if target_signed { 'i' } else { 'u' }
735                ),
736            )),
737            ParseIntRadixErrorKind::Empty => Err(Rich::custom(
738                span,
739                format!("could not parse `{source}` as a number because it contains no numbers"),
740            )),
741            ParseIntRadixErrorKind::Zero => {
742                Err(Rich::custom(span, "number can't be 0 in this position"))
743            }
744        },
745    }
746}
747
748pub type InputType<'tokens, 'src> =
749    MappedInput<'tokens, Token<'src>, Span, &'tokens [Spanned<Token<'src>>]>;
750pub type RichErr<'tokens, 'src> = Rich<'tokens, Token<'src>, Span>;
751pub type RichExtra<'tokens, 'src> = extra::Full<RichErr<'tokens, 'src>, AstArena, ()>;
752
753pub fn ident<'tokens, 'src: 'tokens>(
754    allow_auto: bool,
755) -> impl Parser<'tokens, InputType<'tokens, 'src>, Ident, RichExtra<'tokens, 'src>> + Clone {
756    select! {
757        Token::Ident(val) = e => Ident::new(val.intern(), e.span()),
758        Token::Underscore = e if allow_auto => Ident::new_auto(e.span()),
759    }
760    .labelled(format!(
761        "Ident{}",
762        if allow_auto { "|Underscore" } else { "" }
763    ))
764    .as_terminal()
765}
766
767pub fn doc_comment<'tokens, 'src: 'tokens>()
768-> impl Parser<'tokens, InputType<'tokens, 'src>, Spanned<Istr>, RichExtra<'tokens, 'src>> + Copy {
769    select! {
770        Token::DocCommentLine(val) => val
771    }
772    .map_with(|line, extra| line.intern().spanned(extra.span()))
773    .labelled("DocCommentLine")
774    .as_terminal()
775}
776
777pub fn num<'tokens, 'src: 'tokens, I: ParseIntRadix>()
778-> impl Parser<'tokens, InputType<'tokens, 'src>, I, RichExtra<'tokens, 'src>> + Clone {
779    select! {
780        Token::Num(num) => num
781    }
782    .try_map(try_num::<I>)
783    .labelled(format!(
784        "Num<{}>",
785        // Get the type name of the integer, excluding module path
786        std::any::type_name::<I>().split("::").last().unwrap()
787    ))
788    .as_terminal()
789}
790
791pub fn range<'tokens, 'src: 'tokens>()
792-> impl Parser<'tokens, InputType<'tokens, 'src>, Expression, RichExtra<'tokens, 'src>> + Clone {
793    num::<i128>()
794        .then_ignore(just(Token::Colon))
795        .then(num::<i128>())
796        .map(|(end, start)| Expression::AddressRange { end, start })
797        .labelled("range")
798}
799
800pub fn base_type<'tokens, 'src: 'tokens>()
801-> impl Parser<'tokens, InputType<'tokens, 'src>, BaseType, RichExtra<'tokens, 'src>> + Copy {
802    select! { Token::BaseType(bt) => bt }
803        .labelled("BaseType")
804        .as_terminal()
805}
806
807pub fn integer<'tokens, 'src: 'tokens>()
808-> impl Parser<'tokens, InputType<'tokens, 'src>, Integer, RichExtra<'tokens, 'src>> + Copy {
809    select! { Token::Integer(i) => i }
810        .labelled("Integer")
811        .as_terminal()
812}
813
814pub fn byte_array<'tokens, 'src: 'tokens>()
815-> impl Parser<'tokens, InputType<'tokens, 'src>, Expression, RichExtra<'tokens, 'src>> + Clone {
816    num::<u8>()
817        .separated_by(just(Token::Comma))
818        .collect::<Vec<_>>()
819        .map(Expression::ByteArray)
820        .then_ignore(just(Token::Comma).or_not())
821        .delimited_by(just(Token::BracketOpen), just(Token::BracketClose))
822        .labelled("byte-array")
823}
824
825/// Expression without type reference since that clashes with nodes
826pub fn simple_expression<'tokens, 'src: 'tokens>()
827-> impl Parser<'tokens, InputType<'tokens, 'src>, Spanned<Expression>, RichExtra<'tokens, 'src>> + Clone
828{
829    choice((
830        range().labelled("range").as_non_terminal(),
831        base_type().map(Expression::BaseType),
832        integer().map(Expression::Integer),
833        num::<i128>().map(Expression::Number),
834        just(Token::Default)
835            .ignore_then(
836                num::<i128>()
837                    .map(Some)
838                    .or(just(Token::Underscore).map(|_| None)),
839            )
840            .map(Expression::DefaultNumber)
841            .labelled("default-number"),
842        just(Token::CatchAll)
843            .ignore_then(
844                num::<i128>()
845                    .map(Some)
846                    .or(just(Token::Underscore).map(|_| None)),
847            )
848            .map(Expression::CatchAllNumber)
849            .labelled("catch-all-number"),
850        byte_array().labelled("byte-array").as_non_terminal(),
851        just(Token::Allow).map(|_| Expression::Allow),
852        select! { Token::Access(val) => val }
853            .map(Expression::Access)
854            .labelled("Access")
855            .as_terminal(),
856        select! { Token::ByteOrder(val) => val }
857            .map(Expression::ByteOrder)
858            .labelled("ByteOrder")
859            .as_terminal(),
860        just(Token::Underscore).map(|_| Expression::Auto),
861        select! { Token::String(val) => val.intern() }
862            .map(Expression::String)
863            .labelled("String")
864            .as_terminal(),
865        select! { Token::AddressMode(val) => val }
866            .map(Expression::AddressMode)
867            .labelled("AddressMode")
868            .as_terminal(),
869    ))
870    .map_with(|expression, extra| expression.spanned(extra.span()))
871    .labelled("simple-expression")
872}
873
874pub fn repeat<'tokens, 'src: 'tokens>()
875-> impl Parser<'tokens, InputType<'tokens, 'src>, Spanned<Repeat>, RichExtra<'tokens, 'src>> + Clone
876{
877    choice((
878        num::<NonZeroU32>().map(RepeatSource::Count),
879        ident(false).map(RepeatSource::Enum),
880    ))
881    .map_with(|repeat_source, extra| repeat_source.with_span(extra.span()))
882    .then(
883        just(Token::Stride)
884            .ignore_then(num::<i32>().map_with(|num, extra| num.with_span(extra.span()))),
885    )
886    .delimited_by(just(Token::BracketOpen), just(Token::BracketClose))
887    .map_with(|(source, stride), extra| Repeat { source, stride }.spanned(extra.span()))
888    .labelled("repeat")
889}
890
891pub fn property<'tokens, 'src: 'tokens, 'node>(
892    node: impl Parser<'tokens, InputType<'tokens, 'src>, NodeId, RichExtra<'tokens, 'src>> + Clone,
893) -> impl Parser<'tokens, InputType<'tokens, 'src>, Spanned<Property>, RichExtra<'tokens, 'src>> + Clone
894{
895    doc_comment()
896        .repeated()
897        .collect()
898        .then(
899            ident(false)
900                .then(
901                    just(Token::Colon).ignore_then(choice((
902                        simple_expression()
903                            .labelled("simple-expression")
904                            .as_non_terminal(),
905                        node.clone()
906                            .map_with(|node, extra| Expression::SubNode(node).spanned(extra.span()))
907                            .labelled("node")
908                            .as_non_terminal(),
909                        ident(false)
910                            .map(Expression::TypeReference)
911                            .map_with(|expression, extra| expression.spanned(extra.span())),
912                    ))),
913                )
914                .map_with(|(name, expression), extra| {
915                    Property {
916                        doc_comments: Vec::new(),
917                        name,
918                        expression,
919                    }
920                    .spanned(extra.span())
921                }),
922        )
923        .map(|(docs, mut prop)| {
924            prop.doc_comments = docs;
925            prop
926        })
927        .labelled("property")
928}
929
930pub fn type_specifier<'tokens, 'src: 'tokens>(
931    node: impl Parser<'tokens, InputType<'tokens, 'src>, NodeId, RichExtra<'tokens, 'src>> + Clone,
932) -> impl Parser<'tokens, InputType<'tokens, 'src>, Spanned<TypeSpecifier>, RichExtra<'tokens, 'src>>
933+ Clone {
934    let type_conversion = just(Token::As).ignore_then(just(Token::Try).or_not()).then(
935        node.labelled("node")
936            .as_non_terminal()
937            .map(TypeConversion::Subnode)
938            .or(ident(false).map(TypeConversion::Reference)),
939    );
940    just(Token::Arrow)
941        .ignore_then(
942            choice((
943                base_type(),
944                integer().map(BaseType::FixedSize),
945                just(Token::Underscore).map(|_| BaseType::Unspecified),
946            ))
947            .map_with(|b, e| b.spanned(e.span())),
948        )
949        .then(type_conversion.or_not())
950        .map(|(base_type, conversion)| TypeSpecifier {
951            base_type,
952            use_try: conversion
953                .as_ref()
954                .map(|(try_token, _)| try_token.is_some())
955                .unwrap_or_default(),
956            conversion: conversion.map(|(_, conversion)| conversion),
957        })
958        .map_with(|ts, e| ts.spanned(e.span()))
959        .labelled("type-specifier")
960}
961
962pub fn node_body<'tokens, 'src: 'tokens>(
963    node: impl Parser<'tokens, InputType<'tokens, 'src>, NodeId, RichExtra<'tokens, 'src>> + Clone,
964) -> impl Parser<
965    'tokens,
966    InputType<'tokens, 'src>,
967    (Vec<Spanned<Property>>, Vec<NodeId>),
968    RichExtra<'tokens, 'src>,
969> + Clone {
970    let properties = property(node.clone())
971        .labelled("property")
972        .as_non_terminal()
973        .separated_by(just(Token::Comma))
974        .at_least(1)
975        .collect::<Vec<_>>();
976    let nodes = node
977        .labelled("node")
978        .as_non_terminal()
979        .separated_by(just(Token::Comma))
980        .at_least(1)
981        .collect::<Vec<_>>();
982
983    // Body with comma forced between properties and nodes
984    choice((
985        // Properties + comma + nodes
986        properties
987            .clone()
988            .then_ignore(just(Token::Comma))
989            .then(nodes.clone()),
990        // Properties + no comma + no nodes
991        properties
992            .clone()
993            .map(|properties| (properties, Vec::new())),
994        // No properties + no comma + nodes
995        nodes.map(|nodes| (Vec::new(), nodes)),
996    ))
997    .then_ignore(just(Token::Comma).or_not())
998    .or_not()
999    .map(|body| body.unwrap_or_default())
1000    .delimited_by(just(Token::CurlyOpen), just(Token::CurlyClose))
1001    .labelled("node-body")
1002}
1003
1004pub fn node<'tokens, 'src: 'tokens>()
1005-> impl Parser<'tokens, InputType<'tokens, 'src>, NodeId, RichExtra<'tokens, 'src>> + Clone {
1006    recursive(|node| {
1007        let node = node.labelled("node").as_non_terminal();
1008
1009        doc_comment()
1010            .repeated()
1011            .collect()
1012            .then(ident(false).labelled("node-type"))
1013            .then(ident(true).labelled("node-name"))
1014            .then(repeat().labelled("repeat").as_non_terminal().or_not())
1015            .then(
1016                simple_expression()
1017                    .labelled("simple-expression")
1018                    .as_non_terminal()
1019                    .repeated()
1020                    .collect::<Vec<_>>(),
1021            )
1022            .then(
1023                type_specifier(node.clone())
1024                    .labelled("type-specifier")
1025                    .as_non_terminal()
1026                    .or_not(),
1027            )
1028            .then(
1029                node_body(node.clone())
1030                    .map_with(|body, extra| (body, extra.span()))
1031                    .labelled("node-body")
1032                    .as_non_terminal()
1033                    .or_not(),
1034            )
1035            .map_with(
1036                |(
1037                    (((((doc_comments, node_type), name), repeat), expressions), type_specifier),
1038                    body,
1039                ),
1040                 extra| {
1041                    let ((properties, sub_nodes), body_span) = body.unwrap_or_default();
1042
1043                    let span: Span = extra.span();
1044
1045                    extra.state().alloc_node(Node {
1046                        doc_comments,
1047                        node_type,
1048                        name,
1049                        repeat,
1050                        type_specifier,
1051                        properties,
1052                        short_properties: expressions,
1053                        sub_nodes,
1054                        body_span: if body_span.is_empty() {
1055                            None
1056                        } else {
1057                            Some(body_span)
1058                        },
1059                        span,
1060                    })
1061                },
1062            )
1063            .labelled("node")
1064    })
1065}