From 4ed2778ab8a6410f4f9ce75805c55db9d34f086f Mon Sep 17 00:00:00 2001 From: Michael <78988079+mhasel@users.noreply.github.com> Date: Fri, 24 Jan 2025 11:18:27 +0100 Subject: [PATCH 1/3] fix: mut_visitor no longer clones (#1394) --- compiler/plc_ast/src/ast.rs | 27 +++- compiler/plc_ast/src/mut_visitor.rs | 186 +++++++++++++++++----------- 2 files changed, 137 insertions(+), 76 deletions(-) diff --git a/compiler/plc_ast/src/ast.rs b/compiler/plc_ast/src/ast.rs index 28e2ea7299..c3fee5fbab 100644 --- a/compiler/plc_ast/src/ast.rs +++ b/compiler/plc_ast/src/ast.rs @@ -2,7 +2,6 @@ use std::{ fmt::{Debug, Display, Formatter}, - hash::Hash, ops::Range, }; @@ -722,8 +721,14 @@ pub struct AstNode { pub location: SourceLocation, } +impl Default for AstNode { + fn default() -> Self { + AstFactory::create_empty_statement(SourceLocation::internal(), usize::MAX) + } +} + #[derive(Debug, Clone, PartialEq, TryInto)] -#[try_into(ref)] +#[try_into(ref, ref_mut, owned)] pub enum AstStatement { EmptyStatement(EmptyStatement), @@ -783,6 +788,20 @@ macro_rules! try_from { }; } +#[macro_export] +/// A `try_from` convenience wrapper for `AstNode`, passed as the `ex:expr` argument. +/// Will try to return a reference to the variants inner type, specified via the `t:ty` parameter. +/// Converts the `try_from`-`Result` into an `Option` +macro_rules! try_from_mut { + () => { None }; + ($ex:expr, $t:ty) => { + <&mut $t>::try_from($ex.get_stmt_mut()).ok() + }; + ($($ex:tt)*, $t:ty) => { + try_from_mut!($($ex)*, $t).ok() + }; +} + impl Debug for AstNode { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match &self.stmt { @@ -932,6 +951,10 @@ impl AstNode { &self.stmt } + pub fn get_stmt_mut(&mut self) -> &mut AstStatement { + &mut self.stmt + } + /// Similar to [`AstNode::get_stmt`] with the exception of peeling parenthesized expressions. /// For example if called on `((1))` this function would return a [`AstStatement::Literal`] ignoring the /// parenthesized expressions altogether. diff --git a/compiler/plc_ast/src/mut_visitor.rs b/compiler/plc_ast/src/mut_visitor.rs index def28ac311..1b71d5a3d2 100644 --- a/compiler/plc_ast/src/mut_visitor.rs +++ b/compiler/plc_ast/src/mut_visitor.rs @@ -1,14 +1,17 @@ //! This module defines the `AstVisitorMut` trait and its associated macros. //! The `AstVisitorMut` trait provides a set of methods for mutably traversing and visiting ASTs +use std::borrow::BorrowMut; + use crate::ast::{ flatten_expression_list, Assignment, AstNode, AstStatement, BinaryExpression, CallStatement, - CompilationUnit, DataType, DataTypeDeclaration, DefaultValue, DirectAccess, EmptyStatement, - HardwareAccess, Implementation, JumpStatement, LabelStatement, MultipliedStatement, Pou, RangeStatement, - ReferenceAccess, ReferenceExpr, UnaryExpression, UserTypeDeclaration, Variable, VariableBlock, + CompilationUnit, DataType, DataTypeDeclaration, DirectAccess, HardwareAccess, Implementation, + JumpStatement, MultipliedStatement, Pou, RangeStatement, ReferenceAccess, ReferenceExpr, UnaryExpression, + UserTypeDeclaration, Variable, VariableBlock, }; use crate::control_statements::{AstControlStatement, ConditionalBlock, ReturnStatement}; use crate::literals::AstLiteral; +use crate::try_from_mut; #[macro_export] macro_rules! visit_all_nodes_mut { @@ -25,7 +28,7 @@ macro_rules! visit_all_nodes_mut { } /// Macro that calls the visitor's `visit` method for every AstNode in the passed sequence of nodes. -macro_rules! visit_nodes { +macro_rules! visit_nodes_mut { ($visitor:expr, $($node:expr),*) => { $( $visitor.visit($node); @@ -44,6 +47,12 @@ pub trait AstVisitorMut: Sized { node.walk(self) } + //Takes ownership of the node, manipulates it and returns a new node + fn map(&mut self, mut node: AstNode) -> AstNode { + node.borrow_mut().walk(self); + node + } + fn visit_compilation_unit(&mut self, unit: &mut CompilationUnit) { unit.walk(self) } @@ -80,75 +89,95 @@ pub trait AstVisitorMut: Sized { pou.walk(self); } - fn visit_empty_statement(&mut self, _stmt: &mut EmptyStatement, _node: &mut AstNode) {} + fn visit_empty_statement(&mut self, _node: &mut AstNode) {} - fn visit_default_value(&mut self, _stmt: &mut DefaultValue, _node: &mut AstNode) {} + fn visit_default_value(&mut self, _node: &mut AstNode) {} - fn visit_literal(&mut self, stmt: &mut AstLiteral, _node: &mut AstNode) { + fn visit_literal(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, AstLiteral).expect("Is a literal"); stmt.walk(self) } - fn visit_multiplied_statement(&mut self, stmt: &mut MultipliedStatement, _node: &mut AstNode) { + fn visit_multiplied_statement(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, MultipliedStatement).expect("MultipliedStatement"); stmt.walk(self) } - fn visit_reference_expr(&mut self, stmt: &mut ReferenceExpr, _node: &mut AstNode) { + fn visit_reference_expr(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, ReferenceExpr).expect("ReferenceExpr"); stmt.walk(self) } - fn visit_identifier(&mut self, _stmt: &mut str, _node: &mut AstNode) {} + fn visit_identifier(&mut self, _node: &mut AstNode) {} - fn visit_direct_access(&mut self, stmt: &mut DirectAccess, _node: &mut AstNode) { + fn visit_direct_access(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, DirectAccess).expect("DirectAccess"); stmt.walk(self) } - fn visit_hardware_access(&mut self, stmt: &mut HardwareAccess, _node: &mut AstNode) { + fn visit_hardware_access(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, HardwareAccess).expect("HardwareAccess"); stmt.walk(self) } - fn visit_binary_expression(&mut self, stmt: &mut BinaryExpression, _node: &mut AstNode) { + fn visit_binary_expression(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, BinaryExpression).expect("BinaryExpression"); stmt.walk(self) } - fn visit_unary_expression(&mut self, stmt: &mut UnaryExpression, _node: &mut AstNode) { + fn visit_unary_expression(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, UnaryExpression).expect("UnaryExpression"); stmt.walk(self) } - fn visit_expression_list(&mut self, stmt: &mut Vec, _node: &mut AstNode) { + fn visit_expression_list(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, Vec).expect("Vec"); visit_all_nodes_mut!(self, stmt); } - fn visit_paren_expression(&mut self, inner: &mut AstNode, _node: &mut AstNode) { + fn visit_paren_expression(&mut self, node: &mut AstNode) { + let AstStatement::ParenExpression(inner) = node.get_stmt_mut() else { + unreachable!("Must be ParenExpression"); + }; inner.walk(self) } - fn visit_range_statement(&mut self, stmt: &mut RangeStatement, _node: &mut AstNode) { + fn visit_range_statement(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, RangeStatement).expect("RangeStatement"); stmt.walk(self) } fn visit_vla_range_statement(&mut self, _node: &mut AstNode) {} - fn visit_assignment(&mut self, stmt: &mut Assignment, _node: &mut AstNode) { + fn visit_assignment(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, Assignment).expect("Assignment"); stmt.walk(self) } - fn visit_output_assignment(&mut self, stmt: &mut Assignment, _node: &mut AstNode) { + fn visit_output_assignment(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, Assignment).expect("Assignment"); stmt.walk(self) } - fn visit_ref_assignment(&mut self, stmt: &mut Assignment, _node: &mut AstNode) { + fn visit_ref_assignment(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, Assignment).expect("Assignment"); stmt.walk(self) } - fn visit_call_statement(&mut self, stmt: &mut CallStatement, _node: &mut AstNode) { + fn visit_call_statement(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, CallStatement).expect("CallStatement"); stmt.walk(self) } - fn visit_control_statement(&mut self, stmt: &mut AstControlStatement, _node: &mut AstNode) { + fn visit_control_statement(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, AstControlStatement).expect("AstControlStatement"); stmt.walk(self) } - fn visit_case_condition(&mut self, child: &mut AstNode, _node: &mut AstNode) { + fn visit_case_condition(&mut self, node: &mut AstNode) { + let AstStatement::CaseCondition(child) = node.get_stmt_mut() else { + unreachable!("CaseCondition"); + }; child.walk(self) } @@ -156,11 +185,13 @@ pub trait AstVisitorMut: Sized { fn visit_continue_statement(&mut self, _node: &mut AstNode) {} - fn visit_return_statement(&mut self, stmt: &mut ReturnStatement, _node: &mut AstNode) { + fn visit_return_statement(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, ReturnStatement).expect("ReturnStatement"); stmt.walk(self) } - fn visit_jump_statement(&mut self, stmt: &mut JumpStatement, _node: &mut AstNode) { + fn visit_jump_statement(&mut self, node: &mut AstNode) { + let stmt = try_from_mut!(node, JumpStatement).expect("CallStatement"); stmt.walk(self) } @@ -168,18 +199,13 @@ pub trait AstVisitorMut: Sized { /// # Arguments /// * `stmt` - The unwrapedyped `LabelStatement` node to visit. /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId - fn visit_label_statement(&mut self, _stmt: &mut LabelStatement, _node: &mut AstNode) {} -} + fn visit_label_statement(&mut self, _node: &mut AstNode) {} -/// Helper method that walks through a slice of `ConditionalBlock` and applies the visitor's `walk` method to each node. -fn walk_conditional_blocks(visitor: &mut V, blocks: &mut [ConditionalBlock]) -where - V: AstVisitorMut, -{ - for b in blocks { - visit_nodes!(visitor, &mut b.condition); - visit_all_nodes_mut!(visitor, &mut b.body); - } + /// Visits a `Allocation` node. + /// # Arguments + /// * `stmt` - The unwrapedyped `Allocation` node to visit. + /// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId + fn visit_allocation(&mut self, _node: &mut AstNode) {} } impl WalkerMut for AstLiteral { @@ -223,7 +249,7 @@ impl WalkerMut for DirectAccess { where V: AstVisitorMut, { - visit_nodes!(visitor, &mut self.index); + visit_nodes_mut!(visitor, &mut self.index); } } @@ -241,7 +267,7 @@ impl WalkerMut for BinaryExpression { where V: AstVisitorMut, { - visit_nodes!(visitor, &mut self.left, &mut self.right); + visit_nodes_mut!(visitor, &mut self.left, &mut self.right); } } @@ -250,7 +276,7 @@ impl WalkerMut for UnaryExpression { where V: AstVisitorMut, { - visit_nodes!(visitor, &mut self.value); + visit_nodes_mut!(visitor, &mut self.value); } } @@ -259,7 +285,7 @@ impl WalkerMut for Assignment { where V: AstVisitorMut, { - visit_nodes!(visitor, &mut self.left, &mut self.right); + visit_nodes_mut!(visitor, &mut self.left, &mut self.right); } } @@ -268,7 +294,7 @@ impl WalkerMut for RangeStatement { where V: AstVisitorMut, { - visit_nodes!(visitor, &mut self.start, &mut self.end); + visit_nodes_mut!(visitor, &mut self.start, &mut self.end); } } @@ -277,9 +303,21 @@ impl WalkerMut for CallStatement { where V: AstVisitorMut, { - visit_nodes!(visitor, &mut self.operator); + visit_nodes_mut!(visitor, &mut self.operator); if let Some(params) = &mut self.parameters { - visit_nodes!(visitor, params); + visit_nodes_mut!(visitor, params); + } + } +} + +impl WalkerMut for Vec { + fn walk(&mut self, visitor: &mut V) + where + V: AstVisitorMut, + { + for b in self { + visit_nodes_mut!(visitor, &mut b.condition); + visit_all_nodes_mut!(visitor, &mut b.body); } } } @@ -291,21 +329,21 @@ impl WalkerMut for AstControlStatement { { match self { AstControlStatement::If(stmt) => { - walk_conditional_blocks(visitor, &mut stmt.blocks); + stmt.blocks.walk(visitor); visit_all_nodes_mut!(visitor, &mut stmt.else_block); } AstControlStatement::WhileLoop(stmt) | AstControlStatement::RepeatLoop(stmt) => { - visit_nodes!(visitor, &mut stmt.condition); + visit_nodes_mut!(visitor, &mut stmt.condition); visit_all_nodes_mut!(visitor, &mut stmt.body); } AstControlStatement::ForLoop(stmt) => { - visit_nodes!(visitor, &mut stmt.counter, &mut stmt.start, &mut stmt.end); + visit_nodes_mut!(visitor, &mut stmt.counter, &mut stmt.start, &mut stmt.end); visit_all_nodes_mut!(visitor, &mut stmt.by_step); visit_all_nodes_mut!(visitor, &mut stmt.body); } AstControlStatement::Case(stmt) => { - visit_nodes!(visitor, &mut stmt.selector); - walk_conditional_blocks(visitor, &mut stmt.case_blocks); + visit_nodes_mut!(visitor, &mut stmt.selector); + stmt.case_blocks.walk(visitor); visit_all_nodes_mut!(visitor, &mut stmt.else_block); } } @@ -326,7 +364,7 @@ impl WalkerMut for JumpStatement { where V: AstVisitorMut, { - visit_nodes!(visitor, &mut self.condition, &mut self.target); + visit_nodes_mut!(visitor, &mut self.condition, &mut self.target); } } @@ -335,32 +373,32 @@ impl WalkerMut for AstNode { where V: AstVisitorMut, { - match self.stmt.clone() { - AstStatement::EmptyStatement(ref mut stmt) => visitor.visit_empty_statement(stmt, self), - AstStatement::DefaultValue(ref mut stmt) => visitor.visit_default_value(stmt, self), - AstStatement::Literal(ref mut stmt) => visitor.visit_literal(stmt, self), - AstStatement::MultipliedStatement(ref mut stmt) => visitor.visit_multiplied_statement(stmt, self), - AstStatement::ReferenceExpr(ref mut stmt) => visitor.visit_reference_expr(stmt, self), - AstStatement::Identifier(ref mut stmt) => visitor.visit_identifier(stmt, self), - AstStatement::DirectAccess(ref mut stmt) => visitor.visit_direct_access(stmt, self), - AstStatement::HardwareAccess(ref mut stmt) => visitor.visit_hardware_access(stmt, self), - AstStatement::BinaryExpression(ref mut stmt) => visitor.visit_binary_expression(stmt, self), - AstStatement::UnaryExpression(ref mut stmt) => visitor.visit_unary_expression(stmt, self), - AstStatement::ExpressionList(ref mut stmt) => visitor.visit_expression_list(stmt, self), - AstStatement::ParenExpression(ref mut stmt) => visitor.visit_paren_expression(stmt, self), - AstStatement::RangeStatement(ref mut stmt) => visitor.visit_range_statement(stmt, self), + match self.stmt { + AstStatement::EmptyStatement(_) => visitor.visit_empty_statement(self), + AstStatement::DefaultValue(_) => visitor.visit_default_value(self), + AstStatement::Literal(_) => visitor.visit_literal(self), + AstStatement::MultipliedStatement(_) => visitor.visit_multiplied_statement(self), + AstStatement::ReferenceExpr(_) => visitor.visit_reference_expr(self), + AstStatement::Identifier(_) => visitor.visit_identifier(self), + AstStatement::DirectAccess(_) => visitor.visit_direct_access(self), + AstStatement::HardwareAccess(_) => visitor.visit_hardware_access(self), + AstStatement::BinaryExpression(_) => visitor.visit_binary_expression(self), + AstStatement::UnaryExpression(_) => visitor.visit_unary_expression(self), + AstStatement::ExpressionList(_) => visitor.visit_expression_list(self), + AstStatement::ParenExpression(_) => visitor.visit_paren_expression(self), + AstStatement::RangeStatement(_) => visitor.visit_range_statement(self), AstStatement::VlaRangeStatement => visitor.visit_vla_range_statement(self), - AstStatement::Assignment(ref mut stmt) => visitor.visit_assignment(stmt, self), - AstStatement::OutputAssignment(ref mut stmt) => visitor.visit_output_assignment(stmt, self), - AstStatement::RefAssignment(ref mut stmt) => visitor.visit_ref_assignment(stmt, self), - AstStatement::CallStatement(ref mut stmt) => visitor.visit_call_statement(stmt, self), - AstStatement::ControlStatement(ref mut stmt) => visitor.visit_control_statement(stmt, self), - AstStatement::CaseCondition(ref mut stmt) => visitor.visit_case_condition(stmt, self), - AstStatement::ExitStatement(ref mut _stmt) => visitor.visit_exit_statement(self), - AstStatement::ContinueStatement(ref mut _stmt) => visitor.visit_continue_statement(self), - AstStatement::ReturnStatement(ref mut stmt) => visitor.visit_return_statement(stmt, self), - AstStatement::JumpStatement(ref mut stmt) => visitor.visit_jump_statement(stmt, self), - AstStatement::LabelStatement(ref mut stmt) => visitor.visit_label_statement(stmt, self), + AstStatement::Assignment(_) => visitor.visit_assignment(self), + AstStatement::OutputAssignment(_) => visitor.visit_output_assignment(self), + AstStatement::RefAssignment(_) => visitor.visit_ref_assignment(self), + AstStatement::CallStatement(_) => visitor.visit_call_statement(self), + AstStatement::ControlStatement(_) => visitor.visit_control_statement(self), + AstStatement::CaseCondition(_) => visitor.visit_case_condition(self), + AstStatement::ExitStatement(_) => visitor.visit_exit_statement(self), + AstStatement::ContinueStatement(_) => visitor.visit_continue_statement(self), + AstStatement::ReturnStatement(_) => visitor.visit_return_statement(self), + AstStatement::JumpStatement(_) => visitor.visit_jump_statement(self), + AstStatement::LabelStatement(_) => visitor.visit_label_statement(self), } } } From 89520b98a42eced03d17c6f042432fda59e0f91e Mon Sep 17 00:00:00 2001 From: Michael <78988079+mhasel@users.noreply.github.com> Date: Fri, 24 Jan 2025 11:31:20 +0100 Subject: [PATCH 2/3] feat: add method to register default participants with pipeline (#1392) --- compiler/plc_driver/src/lib.rs | 9 ++-- compiler/plc_driver/src/pipelines.rs | 41 +++++++++++++------ .../plc_driver/src/pipelines/participant.rs | 26 +++--------- compiler/plc_driver/src/runner.rs | 35 +++++++++++----- compiler/plc_driver/src/tests.rs | 1 + compiler/plc_source/src/lib.rs | 4 +- compiler/plc_source/src/source_location.rs | 6 +++ 7 files changed, 71 insertions(+), 51 deletions(-) diff --git a/compiler/plc_driver/src/lib.rs b/compiler/plc_driver/src/lib.rs index 05a7f45ffe..3de119d57b 100644 --- a/compiler/plc_driver/src/lib.rs +++ b/compiler/plc_driver/src/lib.rs @@ -10,8 +10,7 @@ use anyhow::{anyhow, Result}; use pipelines::{ - participant::{CodegenParticipant, InitParticipant}, - AnnotatedProject, BuildPipeline, GeneratedProject, Pipeline, + participant::CodegenParticipant, AnnotatedProject, BuildPipeline, GeneratedProject, Pipeline, }; use std::{ ffi::OsStr, @@ -149,6 +148,7 @@ pub fn compile + AsRef + Debug>(args: &[T]) -> Result<()> { //Parse the arguments let mut pipeline = BuildPipeline::new(args)?; //register participants + pipeline.register_default_participants(); let target = pipeline.compile_parameters.as_ref().and_then(|it| it.target.clone()).unwrap_or_default(); let codegen_participant = CodegenParticipant { compile_options: pipeline.get_compile_options().unwrap(), @@ -163,9 +163,7 @@ pub fn compile + AsRef + Debug>(args: &[T]) -> Result<()> { libraries: pipeline.project.get_libraries().to_vec(), }; pipeline.register_participant(Box::new(codegen_participant)); - let init_participant = - InitParticipant::new(&pipeline.project.get_init_symbol_name(), pipeline.context.provider()); - pipeline.register_mut_participant(Box::new(init_participant)); + let format = pipeline.compile_parameters.as_ref().map(|it| it.error_format).unwrap_or_default(); pipeline.run().map_err(|err| { @@ -198,6 +196,7 @@ pub fn parse_and_annotate( mutable_participants: Vec::default(), participants: Vec::default(), }; + pipeline.register_default_participants(); let project = pipeline.parse()?; let project = pipeline.index(project)?; let project = pipeline.annotate(project)?; diff --git a/compiler/plc_driver/src/pipelines.rs b/compiler/plc_driver/src/pipelines.rs index aa469061e8..6d6e3dd1b0 100644 --- a/compiler/plc_driver/src/pipelines.rs +++ b/compiler/plc_driver/src/pipelines.rs @@ -140,7 +140,9 @@ impl BuildPipeline { let compile_parameters = CompileParameters::parse(args)?; compile_parameters.try_into() } +} +impl BuildPipeline { pub fn register_mut_participant(&mut self, participant: Box) { self.mutable_participants.push(participant) } @@ -148,9 +150,6 @@ impl BuildPipeline { pub fn register_participant(&mut self, participant: Box) { self.participants.push(participant) } -} - -impl BuildPipeline { pub fn get_compile_options(&self) -> Option { self.compile_parameters.as_ref().map(|params| { let location = &self.project.get_location().map(|it| it.to_path_buf()); @@ -245,6 +244,16 @@ impl BuildPipeline { log::info!("{err}") } } + + /// Register all default participants (excluding codegen/linking) + pub fn register_default_participants(&mut self) { + use participant::InitParticipant; + // XXX: should we use a static array of participants? + + let init_participant = + InitParticipant::new(&self.project.get_init_symbol_name(), self.context.provider()); + self.register_mut_participant(Box::new(init_participant)); + } } impl Pipeline for BuildPipeline { @@ -275,6 +284,7 @@ impl Pipeline for BuildPipeline { let annotated_project = self.annotate(indexed_project)?; //TODO : this is post lowering, we might want to control this if let Some(CompileParameters { output_ast: true, .. }) = self.compile_parameters { + println!("{:#?}", annotated_project.units); return Ok(()); } @@ -310,27 +320,31 @@ impl Pipeline for BuildPipeline { self.participants.iter().for_each(|p| { p.pre_index(&project); }); - let project = self.mutable_participants.iter().fold(project, |project, p| p.pre_index(project)); + let project = self.mutable_participants.iter_mut().fold(project, |project, p| p.pre_index(project)); let indexed_project = project.index(self.context.provider()); self.participants.iter().for_each(|p| { p.post_index(&indexed_project); }); - let indexed_project = - self.mutable_participants.iter().fold(indexed_project, |project, p| p.post_index(project)); - Ok(indexed_project) + let project = + self.mutable_participants.iter_mut().fold(indexed_project, |project, p| p.post_index(project)); + + Ok(project) } fn annotate(&mut self, project: IndexedProject) -> Result { self.participants.iter().for_each(|p| { p.pre_annotate(&project); }); - let project = self.mutable_participants.iter().fold(project, |project, p| p.pre_annotate(project)); + let project = + self.mutable_participants.iter_mut().fold(project, |project, p| p.pre_annotate(project)); let annotated_project = project.annotate(self.context.provider()); self.participants.iter().for_each(|p| { p.post_annotate(&annotated_project); }); - let annotated_project = - self.mutable_participants.iter().fold(annotated_project, |project, p| p.post_annotate(project)); + let annotated_project = self + .mutable_participants + .iter_mut() + .fold(annotated_project, |project, p| p.post_annotate(project)); Ok(annotated_project) } @@ -352,7 +366,7 @@ impl Pipeline for BuildPipeline { project .generate_single_module(&context, &compile_options)? .map(|module| { - self.participants.iter().try_fold((), |_, participant| participant.generate(&module)) + self.participants.iter_mut().try_fold((), |_, participant| participant.generate(&module)) }) .unwrap_or(Ok(()))?; } else { @@ -513,8 +527,9 @@ impl ParsedProject { let builtins = plc::builtins::parse_built_ins(id_provider); global_index.import(indexer::index(&builtins)); - let (full_index, unresolvables) = plc::resolver::const_evaluator::evaluate_constants(global_index); - IndexedProject { project: ParsedProject { units }, index: full_index, unresolvables } + //TODO: evaluate constants should probably be a participant + let (index, unresolvables) = plc::resolver::const_evaluator::evaluate_constants(global_index); + IndexedProject { project: ParsedProject { units }, index, unresolvables } } } diff --git a/compiler/plc_driver/src/pipelines/participant.rs b/compiler/plc_driver/src/pipelines/participant.rs index 4229e3844a..1adc3bd8f9 100644 --- a/compiler/plc_driver/src/pipelines/participant.rs +++ b/compiler/plc_driver/src/pipelines/participant.rs @@ -60,22 +60,22 @@ pub trait PipelineParticipant: Sync + Send { pub trait PipelineParticipantMut { /// Implement this to access the project before it gets indexed /// This happens directly after parsing - fn pre_index(&self, parsed_project: ParsedProject) -> ParsedProject { + fn pre_index(&mut self, parsed_project: ParsedProject) -> ParsedProject { parsed_project } /// Implement this to access the project after it got indexed /// This happens directly after the index returns - fn post_index(&self, indexed_project: IndexedProject) -> IndexedProject { + fn post_index(&mut self, indexed_project: IndexedProject) -> IndexedProject { indexed_project } /// Implement this to access the project before it gets annotated /// This happens directly after the constants are evaluated - fn pre_annotate(&self, indexed_project: IndexedProject) -> IndexedProject { + fn pre_annotate(&mut self, indexed_project: IndexedProject) -> IndexedProject { indexed_project } /// Implement this to access the project after it got annotated /// This happens directly after annotations - fn post_annotate(&self, annotated_project: AnnotatedProject) -> AnnotatedProject { + fn post_annotate(&mut self, annotated_project: AnnotatedProject) -> AnnotatedProject { annotated_project } } @@ -204,22 +204,6 @@ impl PipelineParticipant for CodegenParticipant { } } -pub struct LoweringParticipant; - -impl PipelineParticipantMut for LoweringParticipant { - fn pre_index(&self, parsed_project: ParsedProject) -> ParsedProject { - parsed_project - } - - fn post_index(&self, indexed_project: IndexedProject) -> IndexedProject { - indexed_project - } - - fn post_annotate(&self, annotated_project: AnnotatedProject) -> AnnotatedProject { - annotated_project - } -} - pub struct InitParticipant { symbol_name: String, id_provider: IdProvider, @@ -232,7 +216,7 @@ impl InitParticipant { } impl PipelineParticipantMut for InitParticipant { - fn pre_annotate(&self, indexed_project: IndexedProject) -> IndexedProject { + fn pre_annotate(&mut self, indexed_project: IndexedProject) -> IndexedProject { indexed_project.extend_with_init_units(&self.symbol_name, self.id_provider.clone()) } } diff --git a/compiler/plc_driver/src/runner.rs b/compiler/plc_driver/src/runner.rs index 41c3f3230a..e0860ae28d 100644 --- a/compiler/plc_driver/src/runner.rs +++ b/compiler/plc_driver/src/runner.rs @@ -1,4 +1,7 @@ -use crate::{pipelines::ParsedProject, CompileOptions}; +use crate::{ + pipelines::{BuildPipeline, Pipeline}, + CompileOptions, +}; use plc::codegen::{CodegenContext, GeneratedModule}; use plc_diagnostics::diagnostician::Diagnostician; @@ -23,23 +26,34 @@ impl Default for MainType { /// Sources must be `Compilable`, default implementations include `String` and `&str` /// An implementation is also provided for `Vec` /// -pub fn compile(context: &CodegenContext, source: T) -> GeneratedModule<'_> { +pub fn compile(codegen_context: &CodegenContext, source: T) -> GeneratedModule<'_> { let source = source.containers(); let project = Project::new("TestProject".to_string()).with_sources(source); - let ctxt = GlobalContext::new().with_source(project.get_sources(), None).unwrap(); - let mut diagnostician = Diagnostician::null_diagnostician(); - let parsed_project = ParsedProject::parse(&ctxt, &project, &mut diagnostician).unwrap(); - let indexed_project = parsed_project - .index(ctxt.provider()) - .extend_with_init_units(&project.get_init_symbol_name(), ctxt.provider()); - let annotated_project = indexed_project.annotate(ctxt.provider()); + let context = GlobalContext::new().with_source(project.get_sources(), None).unwrap(); + let diagnostician = Diagnostician::null_diagnostician(); + let mut pipeline = BuildPipeline { + context, + project, + diagnostician, + compile_parameters: None, + linker: plc::linker::LinkerType::Internal, + mutable_participants: Default::default(), + participants: Default::default(), + }; + + pipeline.register_default_participants(); + + let project = pipeline.parse().unwrap(); + let project = pipeline.index(project).unwrap(); + let project = pipeline.annotate(project).unwrap(); + let compile_options = CompileOptions { optimization: plc::OptimizationLevel::None, debug_level: plc::DebugLevel::None, ..Default::default() }; - match annotated_project.generate_single_module(context, &compile_options) { + match project.generate_single_module(codegen_context, &compile_options) { Ok(res) => res.unwrap(), Err(e) => panic!("{e}"), } @@ -51,6 +65,7 @@ pub fn compile(context: &CodegenContext, source: T) -> GeneratedM pub fn compile_and_run(source: S, params: &mut T) -> U { let context: CodegenContext = CodegenContext::create(); let module = compile(&context, source); + module.print_to_stderr(); module.run::("main", params) } diff --git a/compiler/plc_driver/src/tests.rs b/compiler/plc_driver/src/tests.rs index c09065162d..5181018872 100644 --- a/compiler/plc_driver/src/tests.rs +++ b/compiler/plc_driver/src/tests.rs @@ -48,6 +48,7 @@ where optimization: plc::OptimizationLevel::None, ..Default::default() }; + //TODO: participants pipelines::ParsedProject::parse(&ctxt, &project, &mut diagnostician)? //Index .index(ctxt.provider()) diff --git a/compiler/plc_source/src/lib.rs b/compiler/plc_source/src/lib.rs index cb7fba1c3e..ecbfc012c9 100644 --- a/compiler/plc_source/src/lib.rs +++ b/compiler/plc_source/src/lib.rs @@ -23,7 +23,7 @@ pub enum SourceType { /// SourceContainers offer source-code to be compiled via the load_source function. /// Furthermore it offers a location-String used when reporting diagnostics. -pub trait SourceContainer: Sync { +pub trait SourceContainer: Sync + Send { /// loads and returns the SourceEntry that contains the SourceCode and the path it was loaded from fn load_source(&self, encoding: Option<&'static Encoding>) -> Result; /// returns the location of this source-container. Used when reporting diagnostics. @@ -88,7 +88,7 @@ impl SourceCodeFactory for &str { } } -impl + Sync> SourceContainer for T { +impl + Sync + Send> SourceContainer for T { fn load_source(&self, encoding: Option<&'static Encoding>) -> Result { let source_type = self.get_type(); if matches!(source_type, SourceType::Text | SourceType::Xml) { diff --git a/compiler/plc_source/src/source_location.rs b/compiler/plc_source/src/source_location.rs index 9b86b73740..91305cf7e9 100644 --- a/compiler/plc_source/src/source_location.rs +++ b/compiler/plc_source/src/source_location.rs @@ -228,6 +228,12 @@ impl Display for SourceLocation { } } +impl Default for SourceLocation { + fn default() -> Self { + Self::internal() + } +} + impl SourceLocation { /// Constructs an undefined SourceRange with a 0..0 range and no filename pub fn undefined() -> SourceLocation { From 245a61ee7732425e5e837ab6abdba9757b70b21b Mon Sep 17 00:00:00 2001 From: Michael Haselberger Date: Fri, 24 Jan 2025 12:15:21 +0100 Subject: [PATCH 3/3] Merge master --- compiler/plc_driver/src/lib.rs | 14 +++++--------- compiler/plc_driver/src/pipelines.rs | 13 +++++++++++++ compiler/plc_driver/src/runner.rs | 14 +++----------- src/tests/adr/pou_adr.rs | 3 --- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/compiler/plc_driver/src/lib.rs b/compiler/plc_driver/src/lib.rs index 759e8473bd..3de119d57b 100644 --- a/compiler/plc_driver/src/lib.rs +++ b/compiler/plc_driver/src/lib.rs @@ -10,8 +10,7 @@ use anyhow::{anyhow, Result}; use pipelines::{ - participant::{CodegenParticipant, InitParticipant}, - AnnotatedProject, BuildPipeline, GeneratedProject, Pipeline, + participant::CodegenParticipant, AnnotatedProject, BuildPipeline, GeneratedProject, Pipeline, }; use std::{ ffi::OsStr, @@ -22,8 +21,8 @@ use std::{ use cli::{CompileParameters, ParameterError}; use plc::{ - codegen::CodegenContext, linker::LinkerType, lowering::calls::AggregateTypeLowerer, output::FormatOption, - DebugLevel, ErrorFormat, OnlineChange, OptimizationLevel, + codegen::CodegenContext, linker::LinkerType, output::FormatOption, DebugLevel, ErrorFormat, OnlineChange, + OptimizationLevel, }; use plc_diagnostics::{diagnostician::Diagnostician, diagnostics::Diagnostic}; @@ -149,6 +148,7 @@ pub fn compile + AsRef + Debug>(args: &[T]) -> Result<()> { //Parse the arguments let mut pipeline = BuildPipeline::new(args)?; //register participants + pipeline.register_default_participants(); let target = pipeline.compile_parameters.as_ref().and_then(|it| it.target.clone()).unwrap_or_default(); let codegen_participant = CodegenParticipant { compile_options: pipeline.get_compile_options().unwrap(), @@ -163,12 +163,7 @@ pub fn compile + AsRef + Debug>(args: &[T]) -> Result<()> { libraries: pipeline.project.get_libraries().to_vec(), }; pipeline.register_participant(Box::new(codegen_participant)); - let init_participant = - InitParticipant::new(&pipeline.project.get_init_symbol_name(), pipeline.context.provider()); - pipeline.register_mut_participant(Box::new(init_participant)); - let aggregate_return_participant = AggregateTypeLowerer::new(pipeline.context.provider()); - pipeline.register_mut_participant(Box::new(aggregate_return_participant)); let format = pipeline.compile_parameters.as_ref().map(|it| it.error_format).unwrap_or_default(); pipeline.run().map_err(|err| { @@ -201,6 +196,7 @@ pub fn parse_and_annotate( mutable_participants: Vec::default(), participants: Vec::default(), }; + pipeline.register_default_participants(); let project = pipeline.parse()?; let project = pipeline.index(project)?; let project = pipeline.annotate(project)?; diff --git a/compiler/plc_driver/src/pipelines.rs b/compiler/plc_driver/src/pipelines.rs index 4fe0569a0e..db3041117a 100644 --- a/compiler/plc_driver/src/pipelines.rs +++ b/compiler/plc_driver/src/pipelines.rs @@ -244,6 +244,19 @@ impl BuildPipeline { log::info!("{err}") } } + + /// Register all default participants (excluding codegen/linking) + pub fn register_default_participants(&mut self) { + use participant::InitParticipant; + use plc::lowering::calls::AggregateTypeLowerer; + + let init_participant = + InitParticipant::new(&self.project.get_init_symbol_name(), self.context.provider()); + self.register_mut_participant(Box::new(init_participant)); + + let aggregate_return_participant = AggregateTypeLowerer::new(self.context.provider()); + self.register_mut_participant(Box::new(aggregate_return_participant)); + } } impl Pipeline for BuildPipeline { diff --git a/compiler/plc_driver/src/runner.rs b/compiler/plc_driver/src/runner.rs index 41a080e9d8..e0860ae28d 100644 --- a/compiler/plc_driver/src/runner.rs +++ b/compiler/plc_driver/src/runner.rs @@ -1,12 +1,9 @@ use crate::{ - pipelines::{participant::InitParticipant, BuildPipeline, Pipeline}, + pipelines::{BuildPipeline, Pipeline}, CompileOptions, }; -use plc::{ - codegen::{CodegenContext, GeneratedModule}, - lowering::calls::AggregateTypeLowerer, -}; +use plc::codegen::{CodegenContext, GeneratedModule}; use plc_diagnostics::diagnostician::Diagnostician; use plc_index::GlobalContext; use project::project::Project; @@ -44,12 +41,7 @@ pub fn compile(codegen_context: &CodegenContext, source: T) -> Ge participants: Default::default(), }; - let init_participant = - InitParticipant::new(&pipeline.project.get_init_symbol_name(), pipeline.context.provider()); - pipeline.register_mut_participant(Box::new(init_participant)); - - let aggregate_return_participant = AggregateTypeLowerer::new(pipeline.context.provider()); - pipeline.register_mut_participant(Box::new(aggregate_return_participant)); + pipeline.register_default_participants(); let project = pipeline.parse().unwrap(); let project = pipeline.index(project).unwrap(); diff --git a/src/tests/adr/pou_adr.rs b/src/tests/adr/pou_adr.rs index 1ed2d32e9d..887c8d3f5c 100644 --- a/src/tests/adr/pou_adr.rs +++ b/src/tests/adr/pou_adr.rs @@ -26,7 +26,6 @@ use crate::test_utils::tests::{annotate_with_ids, codegen, index_with_ids}; /// Programs are POUs with exactly one (static) instance. Programs have a persistent state for VAR, VAR_INPUT, /// VAR_OUTPUT and VAR_IN_OUT variables. The instance is statically available and behaves as if there is a callable /// global variable withe the program's name. When calling a program all parameters, except IN_OUT parameters, are optional. - const DEFAULT_PRG: &str = r#" PROGRAM main_prg VAR_INPUT i : INT END_VAR @@ -378,7 +377,6 @@ fn calling_a_program() { /// that you can have mulitple instances of a FunctionBlock. Therefore a FunctionBlocks instance variable is not /// auto-generated as a global variable as it would be for a program. FB-instances can be declared as part of your /// code. A FunctionBlock acts automatically as a DataType. - const DEFAULT_FB: &str = r#" FUNCTION_BLOCK main_fb VAR_INPUT i : INT := 6 END_VAR @@ -554,7 +552,6 @@ fn calling_a_function_block() { /// /// Functions are stateless methods. They dont have an instance-struct or instance variables. Functions /// take all their parameters passed one by one to the function. - const DEFAULT_FUNC: &str = r#" FUNCTION main_fun : DINT VAR_INPUT i : INT; END_VAR