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