ligen_python_parser/
literal.rs

1use rustpython_parser::ast::{Constant, ExprConstant, Expr};
2use ligen::ir::Literal;
3use ligen::parser::{Parser, ParserConfig};
4use crate::prelude::*;
5
6#[derive(Default)]
7pub struct LiteralParser {}
8
9impl ligen::parser::universal::literal::LiteralParser for LiteralParser {}
10
11impl Parser<String> for LiteralParser {
12    type Output = Literal;
13    fn parse(&self, input: String, config: &ParserConfig) -> Result<Self::Output> {
14        self.parse(input.as_str(), config)
15    }
16}
17
18impl Parser<&str> for LiteralParser {
19    type Output = Literal;
20    fn parse(&self, input: &str, config: &ParserConfig) -> Result<Self::Output> {
21        if let Ok(integer) = input.parse::<i64>() {
22            Ok(Literal::Integer(integer))
23        } else {
24            ExprConstant::parse(input, "<embedded>")
25                .map_err(|e| Error::Message(format!("Failed to parse literal from ExprConstant: {:?}", e)))
26                .and_then(|constant| self.parse(&constant, config))
27        }
28    }
29}
30
31impl Parser<&Constant> for LiteralParser {
32    type Output = Literal;
33    fn parse(&self, input: &Constant, _config: &ParserConfig) -> Result<Self::Output> {
34        match input {
35            Constant::Bool(bool) => Ok(Literal::Boolean(*bool)),
36            Constant::Float(float) => Ok(Literal::Float(*float)),
37            Constant::Str(string) => Ok(Literal::String(string.clone())),
38            Constant::Int(big_int) => Ok(
39                Literal::Integer(
40                    big_int
41                        .try_into()
42                        .map_err(|_| Error::Message("Failed to convert BigInt to usize".into()))?
43                    )
44                ),
45            Constant::None => Ok(Literal::None),
46            Constant::Tuple(tuple) => {
47                let mut result = Vec::new();
48                for element in tuple {
49                    result.push(self.parse(element, _config)?);
50                }
51                Ok(Literal::Tuple(result))
52            },
53            _ => Err(Error::Message(format!("Failed to parse literal from constant: {:?}", input)))
54        }
55    }
56}
57
58impl Parser<&ExprConstant> for LiteralParser {
59    type Output = Literal;
60    fn parse(&self, input: &ExprConstant, config: &ParserConfig) -> Result<Self::Output> {
61        self.parse(&input.value, config)
62    }
63}
64
65impl Parser<&Expr> for LiteralParser {
66    type Output = Literal;
67    fn parse(&self, input: &Expr, config: &ParserConfig) -> Result<Self::Output> {
68        match input {
69            Expr::Constant(constant) => self.parse(constant, config),
70            Expr::List(list) => {
71                let mut result = Vec::new();
72                for element in &list.elts {
73                    result.push(self.parse(element, config)?);
74                }
75                Ok(Literal::Vector(result))
76            },
77            _ => Ok(Literal::Unknown("Unimplemented".into()))
78        }
79    }
80}
81
82#[cfg(test)]
83mod test {
84    use crate::literal::LiteralParser;
85    use crate::prelude::*;
86    use ligen::ir::literal::mock;
87    use ligen::parser::assert::*;
88
89    #[test]
90    fn literal_string() -> Result<()> {
91        assert_eq(LiteralParser::default(), mock::literal_string(), "\"string\"")
92    }
93
94    #[test]
95    fn literal_bool() -> Result<()> {
96        assert_eq(LiteralParser::default(), mock::literal_bool(), "False")
97    }
98
99    #[test]
100    fn literal_integer() -> Result<()> {
101        assert_eq(LiteralParser::default(), mock::literal_integer(), "-2")
102    }
103
104    #[test]
105    fn literal_float() -> Result<()> {
106        assert_eq(LiteralParser::default(), mock::literal_float(), "3.5")
107    }
108}