Skip to content

Commit 7c014a2

Browse files
committed
VTable Generation
1 parent 15331ae commit 7c014a2

File tree

10 files changed

+2485
-8
lines changed

10 files changed

+2485
-8
lines changed

compiler/plc_ast/src/ast.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,14 @@ impl PouType {
395395
pub fn is_stateful(&self) -> bool {
396396
matches!(self, PouType::FunctionBlock | PouType::Program | PouType::Class)
397397
}
398+
399+
pub fn is_class(&self) -> bool {
400+
matches!(self, PouType::Class)
401+
}
402+
403+
pub fn is_function_block(&self) -> bool {
404+
matches!(self, PouType::FunctionBlock)
405+
}
398406
}
399407

400408
#[derive(Debug, PartialEq, Clone)]
@@ -442,6 +450,18 @@ impl CompilationUnit {
442450
}
443451
}
444452

453+
pub fn internal(name: &'static str) -> Self {
454+
CompilationUnit {
455+
global_vars: Vec::new(),
456+
var_config: Vec::new(),
457+
pous: Vec::new(),
458+
implementations: Vec::new(),
459+
interfaces: Vec::new(),
460+
user_types: Vec::new(),
461+
file: FileMarker::Internal(name),
462+
}
463+
}
464+
445465
pub fn with_implementations(mut self, implementations: Vec<Implementation>) -> Self {
446466
self.implementations = implementations;
447467
self
@@ -504,6 +524,10 @@ pub struct VariableBlock {
504524
}
505525

506526
impl VariableBlock {
527+
pub fn global() -> Self {
528+
VariableBlock::default().with_block_type(VariableBlockType::Global)
529+
}
530+
507531
pub fn with_block_type(mut self, block_type: VariableBlockType) -> Self {
508532
self.kind = block_type;
509533
self
@@ -611,6 +635,14 @@ impl From<&DataTypeDeclaration> for SourceLocation {
611635
}
612636

613637
impl DataTypeDeclaration {
638+
pub fn reference<T, U>(name: T, location: U) -> DataTypeDeclaration
639+
where
640+
T: Into<String>,
641+
U: Into<SourceLocation>,
642+
{
643+
DataTypeDeclaration::Reference { referenced_type: name.into(), location: location.into() }
644+
}
645+
614646
pub fn get_name(&self) -> Option<&str> {
615647
match self {
616648
Self::Aggregate { referenced_type, .. }

compiler/plc_driver/src/pipelines.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,15 @@ use plc::{
2424
codegen::{CodegenContext, GeneratedModule},
2525
index::{indexer, FxIndexSet, Index},
2626
linker::LinkerType,
27-
lowering::{
28-
property::PropertyLowerer,
29-
{calls::AggregateTypeLowerer, InitVisitor},
30-
},
27+
lowering::{calls::AggregateTypeLowerer, property::PropertyLowerer, InitVisitor},
3128
output::FormatOption,
3229
parser::parse_file,
3330
resolver::{
3431
const_evaluator::UnresolvableConstant, AnnotationMapImpl, AstAnnotations, Dependency, StringLiterals,
3532
TypeAnnotator,
3633
},
3734
validation::Validator,
35+
vtable::VTableGenerator,
3836
ConfigFormat, ErrorFormat, OnlineChange, Target, Threads,
3937
};
4038
use plc_diagnostics::{
@@ -263,6 +261,7 @@ impl<T: SourceContainer> BuildPipeline<T> {
263261
Box::new(InitParticipant::new(self.project.get_init_symbol_name(), self.context.provider())),
264262
Box::new(AggregateTypeLowerer::new(self.context.provider())),
265263
Box::new(InheritanceLowerer::new(self.context.provider())),
264+
Box::new(VTableGenerator::new(self.context.provider())),
266265
];
267266

268267
for participant in mut_participants {

compiler/plc_driver/src/pipelines/participant.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use std::{
1313

1414
use ast::provider::IdProvider;
1515
use plc::{
16-
codegen::GeneratedModule, lowering::calls::AggregateTypeLowerer, output::FormatOption, ConfigFormat,
17-
OnlineChange, Target,
16+
codegen::GeneratedModule, lowering::calls::AggregateTypeLowerer, output::FormatOption,
17+
vtable::VTableGenerator, ConfigFormat, OnlineChange, Target,
1818
};
1919
use plc_diagnostics::diagnostics::Diagnostic;
2020
use plc_lowering::inheritance::InheritanceLowerer;
@@ -281,3 +281,14 @@ impl PipelineParticipantMut for AggregateTypeLowerer {
281281
indexed_project.annotate(self.id_provider.clone())
282282
}
283283
}
284+
285+
impl PipelineParticipantMut for VTableGenerator {
286+
fn post_index(&mut self, indexed_project: IndexedProject) -> IndexedProject {
287+
let IndexedProject { mut project, index, .. } = indexed_project;
288+
289+
let mut gen = VTableGenerator::new(self.id_provider.clone());
290+
gen.generate_vtables(&index, &mut project.units); // XXX: The index could also be part of the VTableGenerator
291+
292+
project.index(self.id_provider.clone())
293+
}
294+
}

compiler/plc_source/src/source_location.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,15 @@ impl SourceLocation {
289289
let SourceLocation { span, file } = self;
290290
SourceLocation { span, file: FileMarker::Internal(file.get_name().unwrap_or_default()) }
291291
}
292+
293+
pub fn into_internal_with_file(self) -> Self {
294+
let SourceLocation { file, .. } = self;
295+
SourceLocation {
296+
span: CodeSpan::None,
297+
file: FileMarker::Internal(file.get_name().unwrap_or_default()),
298+
}
299+
}
300+
292301
/// Constructs an undefined SourceRange with a 0..0 range and no filename
293302
pub fn undefined() -> SourceLocation {
294303
SourceLocation { span: CodeSpan::None, file: FileMarker::default() }

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ mod test_utils;
4646

4747
pub mod typesystem;
4848
pub mod validation;
49+
pub mod vtable;
4950
extern crate shell_words;
5051

5152
pub const DEFAULT_DWARF_VERSION: usize = 5;

src/parser.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use crate::{
2828
self, ParseSession,
2929
Token::{self, *},
3030
},
31-
typesystem::DINT_TYPE,
31+
typesystem::{DINT_TYPE, VOID_POINTER_INTERNAL_NAME},
3232
};
3333

3434
use self::{
@@ -323,6 +323,29 @@ fn parse_pou(
323323
// parse variable declarations. note that var in/out/inout
324324
// blocks are not allowed inside of class declarations.
325325
let mut variable_blocks = vec![];
326+
327+
// TODO(vosa): This shouldn't be part of the parser, it should be part of the `VTableGenerator` struct; do that before merging
328+
if super_class.is_none() && matches!(kind, PouType::Class | PouType::FunctionBlock) {
329+
variable_blocks.push(VariableBlock {
330+
kind: VariableBlockType::Local,
331+
variables: vec![Variable {
332+
name: "__vtable".into(),
333+
data_type_declaration: DataTypeDeclaration::Reference {
334+
referenced_type: VOID_POINTER_INTERNAL_NAME.into(),
335+
location: SourceLocation::internal(),
336+
},
337+
initializer: None,
338+
address: None,
339+
location: SourceLocation::internal(),
340+
}],
341+
linkage: LinkageType::Internal,
342+
access: AccessModifier::Protected,
343+
constant: false,
344+
retain: false,
345+
location: SourceLocation::internal(),
346+
});
347+
}
348+
326349
let allowed_var_types = [
327350
KeywordVar,
328351
KeywordVarInput,

src/parser/tests/class_parser_tests.rs

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use insta::assert_snapshot;
1+
use insta::{assert_debug_snapshot, assert_snapshot};
22
use plc_ast::ast::{
33
AccessModifier, ArgumentProperty, DeclarationKind, PolymorphismMode, PouType, VariableBlockType,
44
};
@@ -668,3 +668,79 @@ fn function_block_can_only_be_extended_once() {
668668
│ ^^^ Multiple inheritance. POUs can only be extended once.
669669
")
670670
}
671+
672+
#[test]
673+
fn base_pous_have_embedded_vtables() {
674+
let source = r"
675+
CLASS BaseClass
676+
END_CLASS
677+
678+
FUNCTION_BLOCK BaseFb
679+
END_FUNCTION_BLOCK
680+
";
681+
682+
let (unit, diagnostics) = parse(source);
683+
684+
assert_eq!(diagnostics, Vec::new());
685+
686+
// CLASS
687+
assert_debug_snapshot!(unit.pous[0].variable_blocks, @r#"
688+
[
689+
VariableBlock {
690+
variables: [
691+
Variable {
692+
name: "__vtable",
693+
data_type: DataTypeReference {
694+
referenced_type: "__VOID_POINTER",
695+
},
696+
},
697+
],
698+
variable_block_type: Local,
699+
},
700+
]
701+
"#);
702+
703+
// FUNCTION_BLOCK
704+
assert_debug_snapshot!(unit.pous[0].variable_blocks, @r#"
705+
[
706+
VariableBlock {
707+
variables: [
708+
Variable {
709+
name: "__vtable",
710+
data_type: DataTypeReference {
711+
referenced_type: "__VOID_POINTER",
712+
},
713+
},
714+
],
715+
variable_block_type: Local,
716+
},
717+
]
718+
"#);
719+
}
720+
721+
#[test]
722+
fn extended_pous_do_not_have_embedded_vtable() {
723+
let source = r"
724+
CLASS BaseClass
725+
END_CLASS
726+
727+
FUNCTION_BLOCK BaseFb
728+
END_FUNCTION_BLOCK
729+
730+
CLASS ChildClass EXTENDS BaseClass
731+
END_CLASS
732+
733+
FUNCTION_BLOCK ChildFb EXTENDS BaseFb
734+
END_FUNCTION_BLOCK
735+
";
736+
737+
let (unit, diagnostics) = parse(source);
738+
739+
assert_eq!(diagnostics, Vec::new());
740+
741+
// CLASS
742+
assert_debug_snapshot!(unit.pous[2].variable_blocks, @"[]");
743+
744+
// FUNCTION_BLOCK
745+
assert_debug_snapshot!(unit.pous[3].variable_blocks, @"[]");
746+
}

src/typesystem.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ pub const WCHAR_TYPE: &str = "WCHAR";
9191
pub const VOID_TYPE: &str = "VOID";
9292
pub const VOID_INTERNAL_NAME: &str = "__VOID";
9393
pub const __VLA_TYPE: &str = "__VLA";
94+
pub const VOID_POINTER_INTERNAL_NAME: &str = "__VOID_POINTER";
9495

9596
#[cfg(test)]
9697
mod tests;
@@ -871,6 +872,18 @@ pub fn get_builtin_types() -> Vec<DataType> {
871872
nature: TypeNature::Any,
872873
location: SourceLocation::internal(),
873874
},
875+
DataType {
876+
name: VOID_POINTER_INTERNAL_NAME.into(),
877+
initial_value: None,
878+
information: DataTypeInformation::Pointer {
879+
name: VOID_POINTER_INTERNAL_NAME.into(),
880+
inner_type_name: VOID_INTERNAL_NAME.into(),
881+
auto_deref: None,
882+
type_safe: false,
883+
},
884+
nature: TypeNature::Any,
885+
location: SourceLocation::internal(),
886+
},
874887
DataType {
875888
name: "__VLA".into(),
876889
initial_value: None,

src/validation/types.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ pub fn visit_data_type_declaration<T: AnnotationMap>(
1515
declaration: &DataTypeDeclaration,
1616
context: &ValidationContext<T>,
1717
) {
18+
if declaration.get_location().is_internal() {
19+
return;
20+
}
21+
1822
match declaration {
1923
DataTypeDeclaration::Reference { referenced_type, location } => {
2024
if context.index.find_effective_type_by_name(referenced_type).is_none() {
@@ -55,6 +59,10 @@ pub fn visit_data_type<T: AnnotationMap>(
5559
}
5660

5761
fn validate_data_type(validator: &mut Validator, data_type: &DataType, location: &SourceLocation) {
62+
if location.is_internal() {
63+
return;
64+
}
65+
5866
match data_type {
5967
DataType::StructType { variables, .. } => {
6068
if variables.is_empty() {

0 commit comments

Comments
 (0)