ligen_python_parser/scope/
mod.rs1mod 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
8pub 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}