ligen_python_parser/scope/
mod.rs

1mod import_parser;
2mod scope_type;
3
4use rustpython_parser::ast::{Arguments, Expr, Stmt};
5use ligen::{ir::{Interface, Object, Function, Method, Import, TypeDefinition}, parser::ParserConfig};
6use crate::{prelude::*, parser::PythonParserConfig};
7
8// TODO: REMOVE THIS.
9// pub use import_parser::*;
10pub use scope_type::*;
11use crate::parser::PythonParser;
12
13impl Parser<WithSource<&[Stmt]>> for PythonParser {
14    type Output = Scope;
15    fn parse(&self, input: WithSource<&[Stmt]>, config: &ParserConfig) -> Result<Self::Output> {
16        let imports = self.parse_imports(&input, config)?;
17        let objects = self.parse_objects(&input, config)?;
18        let types = self.parse_types(&input, config)?;
19        let functions = self.parse_functions(&input, config)?;
20        let interfaces = self.parse_interfaces(&input, config)?;
21        let methods = self.parse_methods(&input, config)?;
22        let scope = Scope { imports, objects, types, functions, methods, interfaces };
23        let sub_scopes = self.parse_sub_scopes(&input, config)?;
24        let scope = self.join_scopes(scope, sub_scopes);
25        Ok(scope)
26    }
27}
28
29impl PythonParser {
30    fn join_scopes(&self, mut scope: Scope, sub_scopes: Vec<Scope>) -> Scope {
31        for sub_scope in sub_scopes {
32            scope.join(sub_scope)
33        }
34        scope.objects = self.deduplicate_objects(scope.objects);
35        scope
36    }
37
38    fn deduplicate_objects(&self, objects: Vec<Object>) -> Vec<Object> {
39        let mut deduplicated_objects: Vec<Object> = Vec::new();
40        for object in objects.into_iter().rev() {
41            if !deduplicated_objects.iter().any(|deduplicated_object| deduplicated_object.identifier == object.identifier) {
42                deduplicated_objects.push(object)
43            }
44        }
45        deduplicated_objects
46    }
47
48    fn parse_sub_scopes(&self, statements: &WithSource<&[Stmt]>, config: &ParserConfig) -> Result<Vec<Scope>> {
49        let mut sub_scopes = Vec::new();
50        for statement in statements.ast {
51            match statement {
52                Stmt::If(ast) => {
53                    sub_scopes.push(self.parse(statements.sub( ast.body.as_slice()), config)?);
54                    sub_scopes.push(self.parse(statements.sub(ast.orelse.as_slice()), config)?);
55                },
56                Stmt::Try(ast) => {
57                    sub_scopes.push(self.parse(statements.sub(ast.body.as_slice()), config)?);
58                    sub_scopes.push(self.parse(statements.sub(ast.orelse.as_slice()), config)?);
59                    sub_scopes.push(self.parse(statements.sub(ast.finalbody.as_slice()), config)?);
60                },
61                _ => ()
62            }
63        }
64        Ok(sub_scopes)
65    }
66
67    fn has_static_decorator(&self, decorator_list: WithSource<&[Expr]>) -> bool {
68        decorator_list
69            .ast
70            .iter()
71            .filter_map(|expr| match expr {
72                Expr::Call(call) => call.func.as_name_expr(),
73                _ => None
74            })
75            .any(|decorator| decorator.id.as_str() == "staticmethod")
76    }
77
78    fn has_self(&self, arguments: WithSource<&Arguments>) -> bool {
79        arguments
80            .ast
81            .args
82            .first()
83            .map(|argument| argument.def.arg.as_str() == "self")
84            .unwrap_or(false)
85    }
86
87    fn is_static_method(&self, statement: WithSource<&Stmt>) -> bool {
88        match statement.ast {
89            Stmt::FunctionDef(function) => {
90                self.has_static_decorator(statement.sub(&function.decorator_list)) || !self.has_self(statement.sub(&function.args))
91            },
92            Stmt::AsyncFunctionDef(function) => {
93                self.has_static_decorator(statement.sub(&function.decorator_list)) || !self.has_self(statement.sub(&function.args))
94            },
95            _ => false
96        }
97    }
98
99    fn parse_functions(&self, statements: &WithSource<&[Stmt]>, config: &ParserConfig) -> Result<Vec<Function>> {
100        let mut functions = Vec::new();
101        for statement in statements.ast {
102            if self.is_static_method(statements.sub(statement)) {
103                match statement {
104                    Stmt::FunctionDef(function) => {
105                        if let Ok(function) = self.function_parser.parse(statements.sub(function.clone()), config) {
106                            functions.push(function)
107                        }
108                    },
109                    Stmt::AsyncFunctionDef(function) => {
110                        if let Ok(function) = self.function_parser.parse(statements.sub(function.clone()), config) {
111                            functions.push(function)
112                        }
113                    },
114                    _ => (),
115                }
116            }
117        }
118        Ok(functions)
119    }
120
121    fn parse_methods(&self, statements: &WithSource<&[Stmt]>, config: &ParserConfig) -> Result<Vec<Method>> {
122        let mut methods = Vec::new();
123        for statement in statements.ast {
124            if !self.is_static_method(statements.sub(statement)) {
125                match statement {
126                    Stmt::FunctionDef(function) => {
127                        if let Ok(function) = self.parse(statements.sub(function.clone()), config) {
128                            methods.push(function)
129                        }
130                    },
131                    Stmt::AsyncFunctionDef(function) => {
132                        if let Ok(function) = self.parse(statements.sub(function.clone()), config) {
133                            methods.push(function)
134                        }
135                    },
136                    _ => (),
137                }
138            }
139        }
140        Ok(methods)
141    }
142
143    fn parse_types(&self, statements: &WithSource<&[Stmt]>, config: &ParserConfig) -> Result<Vec<TypeDefinition>> {
144        let mut types = Vec::new();
145        for statement in statements.ast {
146            if let Stmt::ClassDef(class) = statement {
147                match self.type_definition_parser.parse(statements.sub(class.clone()), config) {
148                    Ok(type_definition) => types.push(type_definition),
149                    Err(error) => todo!("Failed to parse type definition: {:?}", error)
150                }
151            }
152        }
153        Ok(types)
154    }
155
156    fn parse_interfaces(&self, statements: &WithSource<&[Stmt]>, config: &ParserConfig) -> Result<Vec<Interface>> {
157        let mut interfaces = Vec::new();
158        for statement in statements.ast {
159            if let Stmt::ClassDef(class) = statement {
160                if let Ok(interface) = self.parse(WithSource::new(&statements.source, class), config) {
161                    interfaces.push(interface)
162                }
163            }
164        }
165        Ok(interfaces)
166    }
167
168    fn parse_imports(&self, statements: &WithSource<&[Stmt]>, config: &ParserConfig) -> Result<Vec<Import>> {
169        let mut imports = Vec::new();
170        for statement in statements.ast {
171            match statement {
172                Stmt::Import(import) => {
173                    if let Ok(parsed_imports) = self.parse(statements.sub(import), config) {
174                        imports.extend(parsed_imports);
175                    }
176                },
177                Stmt::ImportFrom(import) => {
178                    if let Ok(parsed_imports) = self.parse(statements.sub(import), config) {
179                        imports.extend(parsed_imports);
180                    }
181                },
182                _ => ()
183            }
184        }
185        Ok(imports)
186    }
187
188    fn parse_objects(&self, statements: &WithSource<&[Stmt]>, config: &ParserConfig) -> Result<Vec<Object>> {
189        let mut objects = Vec::new();
190        let class_variables_as_properties = PythonParserConfig::from(config).get_class_variables_as_properties();
191        if !class_variables_as_properties {
192            for statement in statements.ast {
193                match statement {
194                    Stmt::Assign(assign) => {
195                        if let Ok(more_objects) = self.object_parser.parse(assign, config) {
196                            objects.extend(more_objects)
197                        }
198                    },
199                    Stmt::AnnAssign(assign) => {
200                        if let Ok(object) = self.object_parser.parse(statements.sub(assign), config) {
201                            objects.push(object)
202                        }
203                    },
204                    Stmt::AugAssign(assign) => {
205                        if let Ok(object) = self.object_parser.parse(assign, config) {
206                            objects.push(object)
207                        }
208                    },
209                    _ => ()
210                }
211            }
212        }
213        Ok(objects)
214    }
215}