Skip to content

Commit

Permalink
refactor(indexer): introduce SymbolIndexer using the Visitor trait
Browse files Browse the repository at this point in the history
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
riederm committed Jun 13, 2024
1 parent 8eb5dfa commit 2192752
Show file tree
Hide file tree
Showing 12 changed files with 394 additions and 297 deletions.
4 changes: 2 additions & 2 deletions compiler/plc_driver/src/pipelines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ impl<T: SourceContainer + Sync> ParsedProject<T> {
//Preprocess
pre_process(&mut unit, id_provider.clone());
//import to index
let index = plc::index::visitor::visit(&unit);
let index = plc::index::indexer::index(&unit);

(index, unit)
})
Expand All @@ -126,7 +126,7 @@ impl<T: SourceContainer + Sync> ParsedProject<T> {
}
// import builtin functions
let builtins = plc::builtins::parse_built_ins(id_provider);
global_index.import(plc::index::visitor::visit(&builtins));
global_index.import(plc::index::indexer::index(&builtins));

IndexedProject { project: ParsedProject { project: self.project, units }, index: global_index }
}
Expand Down
1 change: 0 additions & 1 deletion src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ pub mod const_expressions;
pub mod indexer;
mod instance_iterator;
pub mod symbol;
pub mod visitor;

#[cfg(test)]
mod tests;
Expand Down
301 changes: 33 additions & 268 deletions src/index/indexer.rs
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
}
6 changes: 2 additions & 4 deletions src/index/indexer/global_var_indexer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use plc_ast::{ast::LinkageType, visitor::AstVisitor};
use plc_ast::ast::LinkageType;

use crate::index::{HardwareBinding, Index, VariableIndexEntry};

Expand All @@ -12,10 +12,8 @@ impl VarGlobalIndexer<'_> {
pub fn new(constant: bool, linkage: LinkageType, index: &mut Index) -> VarGlobalIndexer<'_> {
VarGlobalIndexer { constant, linkage, index }
}
}

impl AstVisitor for VarGlobalIndexer<'_> {
fn visit_variable(&mut self, var: &plc_ast::ast::Variable) {
pub fn visit_variable(&mut self, var: &plc_ast::ast::Variable) {
let target_type = var.data_type_declaration.get_name().unwrap_or_default();
let initializer = self.index.get_mut_const_expressions().maybe_add_constant_expression(
var.initializer.clone(),
Expand Down
Loading

0 comments on commit 2192752

Please sign in to comment.