|
5 | 5 | //!
|
6 | 6 |
|
7 | 7 | use std::{
|
8 |
| - collections::HashMap, |
| 8 | + collections::{HashMap, HashSet}, |
9 | 9 | env, fs,
|
10 | 10 | path::{Path, PathBuf},
|
11 | 11 | sync::{Arc, Mutex, RwLock},
|
12 | 12 | };
|
13 | 13 |
|
14 |
| -use ast::ast::{DataType, DataTypeDeclaration, UserTypeDeclaration}; |
| 14 | +use ast::ast::{DataType, DataTypeDeclaration, Identifier, UserTypeDeclaration}; |
15 | 15 | use ast::{ast::Variable, provider::IdProvider};
|
16 | 16 | use plc::{
|
17 | 17 | codegen::GeneratedModule,
|
18 |
| - index::PouIndexEntry, |
| 18 | + index::{Index, PouIndexEntry}, |
19 | 19 | lowering::calls::AggregateTypeLowerer,
|
20 | 20 | output::FormatOption,
|
21 | 21 | typesystem::{VOID_INTERNAL_NAME, VOID_POINTER_TYPE},
|
@@ -300,48 +300,116 @@ impl VTableIndexer {
|
300 | 300 | format!("__vtable_{name}")
|
301 | 301 | }
|
302 | 302 |
|
303 |
| - fn create_vtable( |
304 |
| - name: &str, |
305 |
| - methods: Vec<&PouIndexEntry>, |
306 |
| - location: SourceLocation, |
307 |
| - ) -> UserTypeDeclaration { |
308 |
| - let mut variables = Vec::new(); |
309 |
| - for method in methods.iter() { |
310 |
| - let variable = Variable { |
311 |
| - name: method.get_name().to_string(), |
312 |
| - data_type_declaration: DataTypeDeclaration::Reference { |
313 |
| - referenced_type: VOID_POINTER_TYPE.into(), |
314 |
| - location: method.get_location().clone(), |
315 |
| - }, |
316 |
| - initializer: None, |
317 |
| - address: None, |
318 |
| - location: method.get_location().clone(), |
319 |
| - }; |
320 |
| - variables.push(variable); |
| 303 | + fn create_vtables_for_pous(index: &Index) -> HashMap<String, UserTypeDeclaration> { |
| 304 | + let mut vtables = HashMap::new(); |
| 305 | + for pou in index.get_pous().values().filter(|pou| pou.is_function_block() || pou.is_class()) { |
| 306 | + let mut variables = Vec::new(); |
| 307 | + |
| 308 | + if let Some(parent) = pou.get_super_class() { |
| 309 | + variables.push(Variable { |
| 310 | + name: VTableIndexer::get_vtable_name(parent), |
| 311 | + data_type_declaration: DataTypeDeclaration::Reference { |
| 312 | + referenced_type: VTableIndexer::get_vtable_name(parent), |
| 313 | + location: SourceLocation::internal(), |
| 314 | + }, |
| 315 | + initializer: None, |
| 316 | + address: None, |
| 317 | + location: SourceLocation::internal(), |
| 318 | + }); |
| 319 | + } |
| 320 | + |
| 321 | + for interface in pou.get_interfaces() { |
| 322 | + variables.push(Variable { |
| 323 | + name: VTableIndexer::get_vtable_name(interface), |
| 324 | + data_type_declaration: DataTypeDeclaration::Reference { |
| 325 | + referenced_type: VTableIndexer::get_vtable_name(interface), |
| 326 | + location: SourceLocation::internal(), |
| 327 | + }, |
| 328 | + initializer: None, |
| 329 | + address: None, |
| 330 | + location: SourceLocation::internal(), |
| 331 | + }); |
| 332 | + } |
| 333 | + |
| 334 | + for method in index.get_methods_local(pou.get_name()) { |
| 335 | + variables.push(VTableIndexer::create_void_pointer(method.get_name())); |
| 336 | + } |
| 337 | + |
| 338 | + vtables |
| 339 | + .insert(pou.get_name().to_string(), VTableIndexer::create_vtable(pou.get_name(), variables)); |
| 340 | + } |
| 341 | + |
| 342 | + vtables |
| 343 | + } |
| 344 | + |
| 345 | + fn create_vtables_for_interfaces(index: &Index) -> HashMap<String, UserTypeDeclaration> { |
| 346 | + let mut vtables = HashMap::new(); |
| 347 | + for interface in index.get_interfaces().values() { |
| 348 | + let mut variables = Vec::new(); |
| 349 | + for Identifier { name, location } in &interface.extensions { |
| 350 | + variables.push(Variable { |
| 351 | + name: VTableIndexer::get_vtable_name(name), |
| 352 | + data_type_declaration: DataTypeDeclaration::Reference { |
| 353 | + referenced_type: VTableIndexer::get_vtable_name(name), |
| 354 | + location: location.clone(), |
| 355 | + }, |
| 356 | + initializer: None, |
| 357 | + address: None, |
| 358 | + location: SourceLocation::internal(), |
| 359 | + }); |
| 360 | + } |
| 361 | + |
| 362 | + for method in interface.get_declared_methods(index) { |
| 363 | + variables.push(VTableIndexer::create_void_pointer(method.get_name())); |
| 364 | + } |
| 365 | + |
| 366 | + vtables.insert( |
| 367 | + interface.get_name().to_string(), |
| 368 | + VTableIndexer::create_vtable(interface.get_name(), variables), |
| 369 | + ); |
| 370 | + } |
| 371 | + |
| 372 | + vtables |
| 373 | + } |
| 374 | + |
| 375 | + /// Creates a void pointer variable with the given name and location |
| 376 | + fn create_void_pointer(name: &str) -> Variable { |
| 377 | + Variable { |
| 378 | + name: name.to_string(), |
| 379 | + data_type_declaration: DataTypeDeclaration::Reference { |
| 380 | + referenced_type: VOID_POINTER_TYPE.into(), |
| 381 | + location: SourceLocation::internal(), |
| 382 | + }, |
| 383 | + initializer: None, |
| 384 | + address: None, |
| 385 | + location: SourceLocation::internal(), |
| 386 | + } |
| 387 | + } |
| 388 | + |
| 389 | + /// Creates a vtable with the given member variables and a mangled name of the form `__vtable_<name>` |
| 390 | + fn create_vtable(name: &str, variables: Vec<Variable>) -> UserTypeDeclaration { |
| 391 | + UserTypeDeclaration { |
| 392 | + data_type: DataType::StructType { name: Some(Self::get_vtable_name(name)), variables }, |
| 393 | + initializer: None, |
| 394 | + location: SourceLocation::internal(), |
| 395 | + scope: Some(name.to_string()), |
321 | 396 | }
|
322 |
| - let data_type = DataType::StructType { name: Some(Self::get_vtable_name(name)), variables }; |
323 |
| - UserTypeDeclaration { data_type, initializer: None, location, scope: Some(name.to_string()) } |
324 | 397 | }
|
325 | 398 | }
|
326 | 399 |
|
327 | 400 | impl PipelineParticipantMut for VTableIndexer {
|
| 401 | + // TODO: Don't track overridden methods in vtable, as they're part of the parent instance (same for interfaces) |
328 | 402 | fn post_index(&mut self, indexed_project: IndexedProject) -> IndexedProject {
|
329 |
| - //For each class or interface, create a vtable type |
330 |
| - //and add it to the index |
331 | 403 | let IndexedProject { mut project, index, .. } = indexed_project;
|
332 |
| - let mut vtables = Vec::new(); |
333 |
| - for interface in index.get_interfaces().values() { |
334 |
| - let methods = interface.get_methods(&index); |
335 |
| - let vtable = Self::create_vtable(interface.get_name(), methods, interface.get_location().clone()); |
336 |
| - vtables.push(vtable); |
337 |
| - } |
338 | 404 |
|
339 |
| - for pou in index.get_pous().values().filter(|it| it.is_function_block() || it.is_class()) { |
340 |
| - let methods = index.get_methods(pou.get_name()); |
341 |
| - let vtable = Self::create_vtable(pou.get_name(), methods, pou.get_location().clone()); |
342 |
| - vtables.push(vtable); |
| 405 | + let vtables_pou = VTableIndexer::create_vtables_for_pous(&index); |
| 406 | + let vtables_intf = VTableIndexer::create_vtables_for_interfaces(&index); |
| 407 | + |
| 408 | + if let Some(unit) = project.units.first_mut() { |
| 409 | + unit.user_types.extend(vtables_pou.into_iter().map(|(_, vtable)| vtable)); |
| 410 | + unit.user_types.extend(vtables_intf.into_iter().map(|(_, vtable)| vtable)); |
343 | 411 | }
|
344 |
| - project.units.first_mut().unwrap().user_types.extend(vtables); |
| 412 | + |
345 | 413 | project.index(self.id_provider.clone())
|
346 | 414 | }
|
347 | 415 | }
|
0 commit comments