ligen_python_parser/function/
mod.rs1pub 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}