microcad_lang/parse/
literal.rs

1// Copyright © 2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4use microcad_core::Integer;
5
6use crate::{parse::*, parser::*, syntax::*};
7
8impl Parse for Refer<Integer> {
9    fn parse(pair: Pair) -> ParseResult<Self> {
10        match pair.as_str().parse::<i64>() {
11            Ok(value) => Ok(Refer::new(value, pair.into())),
12            Err(err) => Err(ParseError::ParseIntError(Refer::new(err, pair.into()))),
13        }
14    }
15}
16
17impl Parse for Literal {
18    fn parse(pair: Pair) -> ParseResult<Self> {
19        Parser::ensure_rule(&pair, Rule::literal);
20
21        let inner = pair.inner().next().expect(INTERNAL_PARSE_ERROR);
22
23        let s = match inner.as_rule() {
24            Rule::number_literal => Literal::Number(NumberLiteral::parse(inner)?),
25            Rule::integer_literal => Literal::Integer(Refer::<Integer>::parse(inner)?),
26            Rule::bool_literal => match inner.as_str() {
27                "true" => Literal::Bool(Refer::new(true, pair.into())),
28                "false" => Literal::Bool(Refer::new(false, pair.into())),
29                _ => unreachable!(),
30            },
31            _ => unreachable!(),
32        };
33
34        Ok(s)
35    }
36}
37
38impl std::str::FromStr for Literal {
39    type Err = ParseError;
40
41    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
42        Parser::parse_rule::<Self>(Rule::literal, s, 0)
43    }
44}
45
46impl Parse for NumberLiteral {
47    fn parse(pair: Pair) -> ParseResult<Self> {
48        Parser::ensure_rule(&pair, Rule::number_literal);
49
50        let mut inner = pair.inner();
51        let number_token = inner.next().expect("Expected number token");
52
53        assert!(
54            number_token.as_rule() == Rule::number
55                || number_token.as_rule() == Rule::integer_literal
56        );
57
58        let value = match number_token.as_str().parse::<f64>() {
59            Ok(value) => value,
60            Err(err) => return Err(ParseError::ParseFloatError(Refer::new(err, pair.src_ref()))),
61        };
62
63        let mut unit = Unit::None;
64
65        if let Some(unit_token) = inner.next() {
66            unit = Unit::parse(unit_token)?;
67        }
68        Ok(NumberLiteral(value, unit, pair.clone().into()))
69    }
70}
71
72impl std::str::FromStr for NumberLiteral {
73    type Err = ParseError;
74
75    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
76        Parser::parse_rule(Rule::number_literal, s, 0)
77    }
78}
79
80impl Parse for Unit {
81    fn parse(pair: Pair) -> ParseResult<Self> {
82        use std::str::FromStr;
83        match Unit::from_str(pair.as_str()) {
84            Ok(unit) => Ok(unit),
85            Err(()) => Err(ParseError::UnknownUnit(Refer::new(
86                pair.as_str().to_string(),
87                pair.into(),
88            ))),
89        }
90    }
91}
92
93impl std::str::FromStr for Unit {
94    type Err = ();
95    fn from_str(s: &str) -> Result<Self, Self::Err> {
96        match s {
97            // Scalars
98            "" => Ok(Self::None),
99            "%" => Ok(Self::Percent),
100
101            // Lengths
102            "m" => Ok(Self::Meter),
103            "cm" => Ok(Self::Centimeter),
104            "mm" => Ok(Self::Millimeter),
105            "µm" => Ok(Self::Micrometer),
106            "in" => Ok(Self::Inch),
107            "\"" => Ok(Self::Inch),
108            "ft" => Ok(Self::Foot),
109            "\'" => Ok(Self::Foot),
110            "yd" => Ok(Self::Yard),
111
112            // Angles
113            "deg" => Ok(Self::Deg),
114            "°" => Ok(Self::DegS),
115            "grad" => Ok(Self::Grad),
116            "turns" => Ok(Self::Turns),
117            "rad" => Ok(Self::Rad),
118
119            // Weights
120            "g" => Ok(Self::Gram),
121            "kg" => Ok(Self::Kilogram),
122            "lb" => Ok(Self::Pound),
123            "oz" => Ok(Self::Ounce),
124
125            // Areas
126            "m²" | "m2" => Ok(Self::Meter2),
127            "cm²" | "cm2" => Ok(Self::Centimeter2),
128            "mm²" | "mm2" => Ok(Self::Millimeter2),
129            "µm²" | "µm2" => Ok(Self::Micrometer2),
130            "in²" | "in2" => Ok(Self::Inch2),
131            "ft²" | "ft2" => Ok(Self::Foot2),
132            "yd²" | "yd2" => Ok(Self::Yard2),
133
134            // Volumes
135            "m³" | "m3" => Ok(Self::Meter3),
136            "cm³" | "cm3" => Ok(Self::Centimeter3),
137            "mm³" | "mm3" => Ok(Self::Millimeter3),
138            "µm³" | "µm3" => Ok(Self::Micrometer3),
139            "in³" | "in3" => Ok(Self::Inch3),
140            "ft³" | "ft3" => Ok(Self::Foot3),
141            "yd³" | "yd3" => Ok(Self::Yard3),
142            "ml" => Ok(Self::Milliliter),
143            "cl" => Ok(Self::Centiliter),
144            "l" => Ok(Self::Liter),
145            "µl" => Ok(Self::Microliter),
146
147            "g/mm³" => Ok(Self::GramPerMillimeter3),
148            "g/m³" => Ok(Self::GramPerMeter3),
149
150            // Unknown
151            _ => Err(()),
152        }
153    }
154}