-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(indexer): introduce SymbolIndexer using the Visitor trait
Replaces the old visitor.rs with indexer.rs and the SymbolIndexer that uses the visitor-trait to visit to nodes that contain symbols. The symbolIndex delegates the actual indexing work to specialized implementations in src/index/indexer/*.rs
- Loading branch information
Showing
12 changed files
with
394 additions
and
297 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,296 +1,61 @@ | ||
use global_var_indexer::VarGlobalIndexer; | ||
use implementation_indexer::ImplementationIndexer; | ||
use plc_ast::{ | ||
ast::{ | ||
ArgumentProperty, DataTypeDeclaration, Implementation, PouType, TypeNature, VariableBlock, | ||
VariableBlockType, | ||
}, | ||
visitor::AstVisitor, | ||
ast::{CompilationUnit, Implementation, VariableBlockType}, | ||
visitor::{AstVisitor, Walker}, | ||
}; | ||
use plc_source::source_location::SourceLocation; | ||
use plc_util::convention::internal_type_name; | ||
use pou_indexer::PouIndexer; | ||
use user_type_indexer::UserTypeIndexer; | ||
|
||
use crate::typesystem; | ||
|
||
use super::{ | ||
ArgumentType, DataTypeInformation, HardwareBinding, Index, MemberInfo, PouIndexEntry, StructSource, | ||
VarArgs, VariableIndexEntry, VariableType, VOID_TYPE, | ||
}; | ||
use super::Index; | ||
|
||
mod global_var_indexer; | ||
mod implementation_indexer; | ||
mod pou_indexer; | ||
mod user_type_indexer; | ||
|
||
/// Indexes all symbols found in the given Compiliation Unit | ||
/// and returns the resulting Index | ||
pub fn index(unit: &CompilationUnit) -> Index { | ||
// let mut index = Index::default(); | ||
let mut indexer = SymbolIndexer::default(); | ||
unit.walk(&mut indexer); | ||
indexer.index | ||
} | ||
|
||
/// Indexer that registers all symbols in the index | ||
#[derive(Default)] | ||
pub struct SymbolIndexer { | ||
pub index: Index, | ||
} | ||
|
||
/// The SymbolIndexer is responsible for registering all delcared types and symbols in the index. | ||
impl AstVisitor for SymbolIndexer { | ||
/// Visits a VAR_GLOBAL VariableBlock and registers all variables as globals in the index | ||
fn visit_variable_block(&mut self, block: &plc_ast::ast::VariableBlock) { | ||
if block.variable_block_type == VariableBlockType::Global { | ||
// let the global var indexer handle the global variables | ||
global_var_indexer::VarGlobalIndexer::new(block.constant, block.linkage, &mut self.index) | ||
.visit_variable_block(block); | ||
let mut indexer = VarGlobalIndexer::new(block.constant, block.linkage, &mut self.index); | ||
for var in &block.variables { | ||
indexer.visit_variable(var); | ||
} | ||
} | ||
} | ||
|
||
/// Visits a user type declaration | ||
/// Registers the user type in the index using the UserTypeIndexer | ||
fn visit_user_type_declaration(&mut self, user_type: &plc_ast::ast::UserTypeDeclaration) { | ||
let mut type_indexer = user_type_indexer::UserTypeIndexer::new(&mut self.index, user_type); | ||
type_indexer.visit_user_type_declaration(user_type); | ||
UserTypeIndexer::new(&mut self.index, user_type).visit_user_type_declaration(user_type); | ||
} | ||
|
||
/// Visits a pou and registers all member variables in the index | ||
/// Also registers the pou's struct type in the index | ||
fn visit_pou(&mut self, pou: &plc_ast::ast::Pou) { | ||
let mut members = vec![]; | ||
|
||
//register the pou's member variables | ||
let mut member_varargs = None; | ||
let mut count = 0; | ||
for block in &pou.variable_blocks { | ||
let block_type = get_declaration_type_for(block, &pou.pou_type); | ||
for var in &block.variables { | ||
let varargs = if let DataTypeDeclaration::DataTypeDefinition { | ||
data_type: plc_ast::ast::DataType::VarArgs { referenced_type, sized }, | ||
.. | ||
} = &var.data_type_declaration | ||
{ | ||
let name = referenced_type | ||
.as_ref() | ||
.map(|it| &**it) | ||
.and_then(DataTypeDeclaration::get_name) | ||
.map(|it| it.to_string()); | ||
Some(if *sized { VarArgs::Sized(name) } else { VarArgs::Unsized(name) }) | ||
} else { | ||
None | ||
}; | ||
|
||
if varargs.is_some() { | ||
member_varargs = varargs.clone(); | ||
} | ||
|
||
let var_type_name = var.data_type_declaration.get_name().unwrap_or(VOID_TYPE); | ||
let type_name = if block_type.is_by_ref() { | ||
//register a pointer type for argument | ||
register_byref_pointer_type_for(&mut self.index, var_type_name) | ||
} else { | ||
var_type_name.to_string() | ||
}; | ||
let initial_value = self.index.get_mut_const_expressions().maybe_add_constant_expression( | ||
var.initializer.clone(), | ||
type_name.as_str(), | ||
Some(pou.name.clone()), | ||
); | ||
|
||
let binding = var.address.as_ref().and_then(|it| { | ||
HardwareBinding::from_statement(&mut self.index, it, Some(pou.name.clone())) | ||
}); | ||
|
||
let entry = self.index.register_member_variable( | ||
MemberInfo { | ||
container_name: &pou.name, | ||
variable_name: &var.name, | ||
variable_linkage: block_type, | ||
variable_type_name: &type_name, | ||
is_constant: block.constant, | ||
binding, | ||
varargs, | ||
}, | ||
initial_value, | ||
var.location.clone(), | ||
count, | ||
); | ||
members.push(entry); | ||
count += 1; | ||
} | ||
} | ||
|
||
//register a function's return type as a member variable | ||
let return_type_name = pou.return_type.as_ref().and_then(|it| it.get_name()).unwrap_or(VOID_TYPE); | ||
if pou.return_type.is_some() { | ||
let entry = self.index.register_member_variable( | ||
MemberInfo { | ||
container_name: &pou.name, | ||
variable_name: pou.get_return_name(), | ||
variable_linkage: ArgumentType::ByVal(VariableType::Return), | ||
variable_type_name: return_type_name, | ||
is_constant: false, //return variables are not constants | ||
binding: None, | ||
varargs: None, | ||
}, | ||
None, | ||
pou.name_location.clone(), | ||
count, | ||
); | ||
members.push(entry); | ||
} | ||
|
||
let has_varargs = member_varargs.is_some(); | ||
let datatype = typesystem::DataType { | ||
name: pou.name.to_string(), | ||
initial_value: None, | ||
information: DataTypeInformation::Struct { | ||
name: pou.name.to_string(), | ||
members, | ||
source: StructSource::Pou(pou.pou_type.clone()), | ||
}, | ||
nature: TypeNature::Any, | ||
location: pou.name_location.clone(), | ||
}; | ||
|
||
match &pou.pou_type { | ||
PouType::Program => { | ||
self.index.register_program(&pou.name, pou.name_location.clone(), pou.linkage); | ||
self.index.register_pou_type(datatype); | ||
} | ||
PouType::FunctionBlock => { | ||
let global_struct_name = crate::index::get_initializer_name(&pou.name); | ||
let variable = VariableIndexEntry::create_global( | ||
&global_struct_name, | ||
&global_struct_name, | ||
&pou.name, | ||
pou.name_location.clone(), | ||
) | ||
.set_constant(true); | ||
self.index.register_global_initializer(&global_struct_name, variable); | ||
self.index.register_pou(PouIndexEntry::create_function_block_entry( | ||
&pou.name, | ||
pou.linkage, | ||
pou.name_location.clone(), | ||
pou.super_class.clone().as_deref(), | ||
)); | ||
self.index.register_pou_type(datatype); | ||
} | ||
PouType::Class => { | ||
let global_struct_name = crate::index::get_initializer_name(&pou.name); | ||
let variable = VariableIndexEntry::create_global( | ||
&global_struct_name, | ||
&global_struct_name, | ||
&pou.name, | ||
pou.name_location.clone(), | ||
) | ||
.set_constant(true); | ||
self.index.register_global_initializer(&global_struct_name, variable); | ||
self.index.register_pou(PouIndexEntry::create_class_entry( | ||
&pou.name, | ||
pou.linkage, | ||
pou.name_location.clone(), | ||
pou.super_class.clone(), | ||
)); | ||
self.index.register_pou_type(datatype); | ||
} | ||
PouType::Function => { | ||
self.index.register_pou(PouIndexEntry::create_function_entry( | ||
&pou.name, | ||
return_type_name, | ||
&pou.generics, | ||
pou.linkage, | ||
has_varargs, | ||
pou.name_location.clone(), | ||
)); | ||
self.index.register_pou_type(datatype); | ||
} | ||
PouType::Method { owner_class } => { | ||
self.index.register_pou(PouIndexEntry::create_method_entry( | ||
&pou.name, | ||
return_type_name, | ||
owner_class, | ||
pou.linkage, | ||
pou.name_location.clone(), | ||
)); | ||
self.index.register_pou_type(datatype); | ||
} | ||
_ => {} | ||
}; | ||
PouIndexer::new(&mut self.index).visit_pou(pou); | ||
} | ||
|
||
/// Visits an implementation and registers the implementation in the index | ||
fn visit_implementation(&mut self, implementation: &Implementation) { | ||
let pou_type = &implementation.pou_type; | ||
let start_location = implementation | ||
.statements | ||
.first() | ||
.map(|it| it.get_location()) | ||
.as_ref() | ||
.or(Some(&implementation.location)) | ||
.cloned() | ||
.unwrap(); | ||
self.index.register_implementation( | ||
&implementation.name, | ||
&implementation.type_name, | ||
pou_type.get_optional_owner_class().as_ref(), | ||
pou_type.into(), | ||
implementation.generic, | ||
start_location, | ||
); | ||
//if we are registing an action, also register a datatype for it | ||
if pou_type == &PouType::Action { | ||
let datatype = typesystem::DataType { | ||
name: implementation.name.to_string(), | ||
initial_value: None, | ||
information: DataTypeInformation::Alias { | ||
name: implementation.name.clone(), | ||
referenced_type: implementation.type_name.clone(), | ||
}, | ||
nature: TypeNature::Derived, | ||
location: implementation.name_location.clone(), | ||
}; | ||
|
||
self.index.register_pou(PouIndexEntry::create_action_entry( | ||
implementation.name.as_str(), | ||
implementation.type_name.as_str(), | ||
implementation.linkage, | ||
implementation.name_location.clone(), | ||
)); | ||
self.index.register_pou_type(datatype); | ||
} | ||
} | ||
} | ||
|
||
/// returns the declaration type (ByRef or ByVal) for the given VariableBlock (VAR_INPUT, VAR_OUTPUT, VAR_INOUT, etc.) | ||
fn get_declaration_type_for(block: &VariableBlock, pou_type: &PouType) -> ArgumentType { | ||
if matches!( | ||
block.variable_block_type, | ||
VariableBlockType::InOut | VariableBlockType::Input(ArgumentProperty::ByRef) | ||
) { | ||
ArgumentType::ByRef(get_variable_type_from_block(block)) | ||
} else if block.variable_block_type == VariableBlockType::Output { | ||
// outputs differ depending on pou type | ||
match pou_type { | ||
PouType::Function => ArgumentType::ByRef(get_variable_type_from_block(block)), | ||
_ => ArgumentType::ByVal(get_variable_type_from_block(block)), | ||
} | ||
} else { | ||
ArgumentType::ByVal(get_variable_type_from_block(block)) | ||
ImplementationIndexer::new(&mut self.index).index_implementation(implementation); | ||
} | ||
} | ||
|
||
fn get_variable_type_from_block(block: &VariableBlock) -> VariableType { | ||
match block.variable_block_type { | ||
VariableBlockType::Local => VariableType::Local, | ||
VariableBlockType::Temp => VariableType::Temp, | ||
VariableBlockType::Input(_) => VariableType::Input, | ||
VariableBlockType::Output => VariableType::Output, | ||
VariableBlockType::Global => VariableType::Global, | ||
VariableBlockType::InOut => VariableType::InOut, | ||
} | ||
} | ||
|
||
/// registers an auto-deref pointer type for the inner_type_name if it does not already exist | ||
fn register_byref_pointer_type_for(index: &mut Index, inner_type_name: &str) -> String { | ||
//get unique name | ||
let type_name = internal_type_name("auto_pointer_to_", inner_type_name); | ||
|
||
//check if type was already created | ||
if index.find_effective_type_by_name(type_name.as_str()).is_none() { | ||
//generate a pointertype for the variable | ||
index.register_type(typesystem::DataType { | ||
name: type_name.clone(), | ||
initial_value: None, | ||
information: DataTypeInformation::Pointer { | ||
name: type_name.clone(), | ||
inner_type_name: inner_type_name.to_string(), | ||
auto_deref: true, | ||
}, | ||
nature: TypeNature::Any, | ||
location: SourceLocation::internal(), | ||
}); | ||
} | ||
|
||
type_name | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.