Skip to main content

vihaco_parser_core/
impls.rs

1// SPDX-FileCopyrightText: 2026 The vihaco Authors
2// SPDX-License-Identifier: MIT
3
4use crate::Parse;
5use chumsky::error::Simple;
6use chumsky::extra;
7use chumsky::prelude::*;
8
9type E<'src> = extra::Err<Simple<'src, char>>;
10
11macro_rules! impl_uint {
12    ($($t:ty),+) => {
13        $(impl<'src> Parse<'src> for $t {
14            fn parser() -> impl Parser<'src, &'src str, Self, E<'src>> {
15                text::int(10).map(|s: &str| s.parse().unwrap())
16            }
17        })+
18    };
19}
20impl_uint!(u64, u32, usize);
21
22macro_rules! impl_sint {
23    ($($t:ty),+) => {
24        $(impl<'src> Parse<'src> for $t {
25            fn parser() -> impl Parser<'src, &'src str, Self, E<'src>> {
26                just('-')
27                    .or_not()
28                    .then(text::int(10))
29                    .to_slice()
30                    .map(|s: &str| s.parse().unwrap())
31            }
32        })+
33    };
34}
35impl_sint!(i64, i32);
36
37macro_rules! impl_float {
38    ($($t:ty),+) => {
39        $(impl<'src> Parse<'src> for $t {
40            fn parser() -> impl Parser<'src, &'src str, Self, E<'src>> {
41                // Accepts: optional unary `-`, integer, optional `.fraction`,
42                // optional `e[+-]?digits`. Real .sst sources include both
43                // scientific-notation literals like `1.9999999999998004e-6`
44                // and negative basis components like `-0.5`; rejecting either
45                // would force every consumer to roll its own float parser.
46                let exp = one_of("eE")
47                    .then(one_of("+-").or_not())
48                    .then(text::digits(10));
49                just('-')
50                    .or_not()
51                    .then(text::int(10))
52                    .then(just('.').then(text::digits(10)).or_not())
53                    .then(exp.or_not())
54                    .to_slice()
55                    .map(|s: &str| s.parse().unwrap())
56            }
57        })+
58    };
59}
60impl_float!(f64, f32);
61
62impl<'src> Parse<'src> for bool {
63    fn parser() -> impl Parser<'src, &'src str, Self, E<'src>> {
64        just("true").to(true).or(just("false").to(false))
65    }
66}
67
68impl<'src> Parse<'src> for String {
69    fn parser() -> impl Parser<'src, &'src str, Self, E<'src>> {
70        any()
71            .filter(|c: &char| !c.is_whitespace())
72            .repeated()
73            .at_least(1)
74            .collect::<String>()
75    }
76}
77
78pub fn ident<'src>() -> impl Parser<'src, &'src str, String, E<'src>> + Clone {
79    any()
80        .filter(|c: &char| {
81            !c.is_whitespace() && !matches!(*c, ',' | ';' | '(' | ')' | '{' | '}' | '[' | ']')
82        })
83        .repeated()
84        .at_least(1)
85        .collect::<String>()
86}