ligen_python_parser/function/
mod.rs

1pub mod parameter;
2pub mod method;
3
4use crate::prelude::*;
5use ligen::parser::ParserConfig;
6use rustpython_parser::ast::{Arguments, Expr, Stmt, StmtAsyncFunctionDef, StmtFunctionDef};
7use ligen::ir::{Function, Synchrony, Visibility, Parameter, Type};
8use crate::function::parameter::ParameterParser;
9use crate::identifier::IdentifierParser;
10use crate::macro_attributes::attributes::AttributesParser;
11use crate::types::type_::TypeParser;
12
13
14#[derive(Default)]
15pub struct FunctionParser {}
16
17impl Parser<&str> for FunctionParser {
18    type Output = Function;
19    fn parse(&self, input: &str, config: &ParserConfig) -> Result<Self::Output> {
20        let statement = Stmt::parse(input, "<embedded>")
21            .map_err(|error| Error::Message(format!("Failed to parse statement: {}", error)))?;
22        match statement {
23            Stmt::FunctionDef(function) => self.parse(WithSource::new(input, function), config),
24            Stmt::AsyncFunctionDef(function) => self.parse(WithSource::new(input, function), config),
25            _ => Err(Error::Message("No function found".into()))
26        }
27    }
28}
29
30impl Parser<WithSource<StmtFunctionDef>> for FunctionParser {
31    type Output = Function;
32    fn parse(&self, input: WithSource<StmtFunctionDef>, config: &ParserConfig) -> Result<Self::Output> {
33        let identifier = IdentifierParser::new().parse(input.ast.name.as_str(), config)?;
34        if config.get_only_parse_symbols() {
35            Ok(Function { identifier, ..Default::default() })
36        } else {
37            let attributes = AttributesParser::default().parse(input.sub(&input.ast.decorator_list), config)?;
38            let visibility = Visibility::Public;
39            let synchrony = Synchrony::Synchronous;
40            let inputs = self.parse_inputs(*input.ast.args, config)?;
41            let output = self.parse_output(input.ast.returns, config)?;
42            Ok(Function { attributes, visibility, synchrony, identifier, inputs, output })    
43        }
44    }
45}
46
47impl Parser<WithSource<StmtAsyncFunctionDef>> for FunctionParser {
48    type Output = Function;
49    fn parse(&self, input: WithSource<StmtAsyncFunctionDef>, config: &ParserConfig) -> Result<Self::Output> {
50        let identifier = IdentifierParser::new().parse(input.ast.name.as_str(), config)?;
51        if config.get_only_parse_symbols() {
52            Ok(Function { identifier, ..Default::default() })
53        } else {
54            let attributes = AttributesParser::default().parse(input.sub(&input.ast.decorator_list), config)?;
55            let visibility = Visibility::Public;
56            let synchrony = Synchrony::Asynchronous;
57            let inputs = self.parse_inputs(*input.ast.args, config)?;
58            let output = self.parse_output(input.ast.returns, config)?;    
59            Ok(Function { attributes, visibility, synchrony, identifier, inputs, output })
60        }
61    }
62}
63
64impl FunctionParser {
65    fn parse_inputs(&self, args: Arguments, config: &ParserConfig) -> Result<Vec<Parameter>> {
66        let mut parameters = Vec::new();
67        for arg in args.args {
68            parameters.push(ParameterParser::default().parse(arg, config)?);
69        }
70        Ok(parameters)
71    }
72
73    fn parse_output(&self, output: Option<Box<Expr>>, config: &ParserConfig) -> Result<Option<Type>> {
74        if let Some(expr) = output.and_then(|expr| expr.name_expr()) {
75            Ok(Some(TypeParser::default().parse(&expr, config)?))
76        } else {
77            Ok(None)
78        }
79    }
80}
81
82#[cfg(test)]
83mod test {
84    use crate::function::FunctionParser;
85    use ligen::prelude::*;
86    use ligen::parser::assert::assert_eq;
87    use ligen_ir::function::mock;
88
89    #[test]
90    fn function() -> Result<()> {
91        assert_eq(FunctionParser::default(), mock::function(), "def test(): pass")
92    }
93
94    #[test]
95    fn function_async() -> Result<()> {
96        assert_eq(FunctionParser::default(), mock::function_async(), "async def test(): pass")
97    }
98
99    #[test]
100    fn function_input() -> Result<()> {
101        assert_eq(FunctionParser::default(), mock::function_input(), "def test(a: int, b: int): pass")
102    }
103
104    #[test]
105    fn function_input_output() -> Result<()> {
106        assert_eq(FunctionParser::default(), mock::function_input_output(), "def test(a: int, b: int) -> int: pass")
107    }
108
109    #[test]
110    fn function_attribute() -> Result<()> {
111        assert_eq(FunctionParser::default(), mock::function_attribute(), "@test(a = 'b')\ndef test(): pass")?;
112        assert_eq(FunctionParser::default(), mock::function_attribute(), "@test(a = \"b\")\ndef test(): pass")
113    }
114}