Skip to content

Commit b5152a8

Browse files
authored
feat: Support jumps and labels from CFC (#969)
* Add jump and label to AST Add tests for the jump impls * Add ast transformation for the jump and label controls * Codegen and validation for jumps and labels
1 parent bca86d2 commit b5152a8

File tree

44 files changed

+2426
-98
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2426
-98
lines changed

compiler/plc_ast/src/ast.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,8 @@ pub enum AstStatement {
616616
ExitStatement(()),
617617
ContinueStatement(()),
618618
ReturnStatement(ReturnStatement),
619+
JumpStatement(JumpStatement),
620+
LabelStatement(LabelStatement),
619621
}
620622

621623
impl Debug for AstNode {
@@ -726,6 +728,12 @@ impl Debug for AstNode {
726728
AstStatement::ReferenceExpr(ReferenceExpr { access, base }) => {
727729
f.debug_struct("ReferenceExpr").field("kind", access).field("base", base).finish()
728730
}
731+
AstStatement::JumpStatement(JumpStatement { condition, target, .. }) => {
732+
f.debug_struct("JumpStatement").field("condition", condition).field("target", target).finish()
733+
}
734+
AstStatement::LabelStatement(LabelStatement { name, .. }) => {
735+
f.debug_struct("LabelStatement").field("name", name).finish()
736+
}
729737
}
730738
}
731739
}
@@ -819,6 +827,13 @@ impl AstNode {
819827
}
820828
}
821829

830+
pub fn get_label_name(&self) -> Option<&str> {
831+
match &self.stmt {
832+
AstStatement::LabelStatement(LabelStatement { name, .. }) => Some(name.as_str()),
833+
_ => None,
834+
}
835+
}
836+
822837
pub fn is_empty_statement(&self) -> bool {
823838
matches!(self.stmt, AstStatement::EmptyStatement(..))
824839
}
@@ -919,6 +934,12 @@ impl AstNode {
919934
pub fn is_default_value(&self) -> bool {
920935
matches!(self.stmt, AstStatement::DefaultValue { .. })
921936
}
937+
938+
/// Negates the given element by adding it to a not expression
939+
pub fn negate(self: AstNode, mut id_provider: IdProvider) -> AstNode {
940+
let location = self.get_location();
941+
AstFactory::create_not_expression(self, location, id_provider.next_id())
942+
}
922943
}
923944

924945
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -1218,7 +1239,7 @@ impl AstFactory {
12181239
}
12191240

12201241
/// creates a not-expression
1221-
pub fn create_not_expression(operator: AstNode, location: SourceLocation, id: AstId) -> AstNode {
1242+
pub fn create_not_expression(operator: AstNode, location: SourceLocation, id: usize) -> AstNode {
12221243
AstNode {
12231244
stmt: AstStatement::UnaryExpression(UnaryExpression {
12241245
value: Box::new(operator),
@@ -1465,6 +1486,19 @@ impl AstFactory {
14651486
id_provider,
14661487
)
14671488
}
1489+
1490+
pub fn create_jump_statement(
1491+
condition: Box<AstNode>,
1492+
target: Box<AstNode>,
1493+
location: SourceLocation,
1494+
id: AstId,
1495+
) -> AstNode {
1496+
AstNode { stmt: AstStatement::JumpStatement(JumpStatement { condition, target }), location, id }
1497+
}
1498+
1499+
pub fn create_label_statement(name: String, location: SourceLocation, id: AstId) -> AstNode {
1500+
AstNode { stmt: AstStatement::LabelStatement(LabelStatement { name }), location, id }
1501+
}
14681502
}
14691503
#[derive(Clone, PartialEq)]
14701504
pub struct EmptyStatement {}
@@ -1532,3 +1566,18 @@ pub struct CallStatement {
15321566
pub operator: Box<AstNode>,
15331567
pub parameters: Option<Box<AstNode>>,
15341568
}
1569+
1570+
/// Represents a conditional jump from current location to a specified label
1571+
#[derive(Clone, Debug, PartialEq)]
1572+
pub struct JumpStatement {
1573+
/// The condition based on which the current statement will perform a jump
1574+
pub condition: Box<AstNode>,
1575+
/// The target location (Label) the statement will jump to
1576+
pub target: Box<AstNode>,
1577+
}
1578+
1579+
/// Represents a location in code that could be jumbed to
1580+
#[derive(Clone, Debug, PartialEq)]
1581+
pub struct LabelStatement {
1582+
pub name: String,
1583+
}

compiler/plc_diagnostics/src/diagnostics.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,14 @@ impl Diagnostic {
614614
Diagnostic::global_name_conflict_with_text(name, location, conflicts, "Duplicate symbol.")
615615
}
616616

617+
pub fn duplicate_label(
618+
name: &str,
619+
location: SourceLocation,
620+
conflicts: Vec<SourceLocation>,
621+
) -> Diagnostic {
622+
Diagnostic::global_name_conflict_with_text(name, location, conflicts, "Duplicate label.")
623+
}
624+
617625
pub fn global_name_conflict_with_text(
618626
name: &str,
619627
location: SourceLocation,
@@ -768,6 +776,14 @@ impl Diagnostic {
768776
err_no: ErrNo::cfc__cyclic_connection,
769777
}
770778
}
779+
780+
pub fn unnamed_control(range: SourceLocation) -> Diagnostic {
781+
Diagnostic::SemanticError {
782+
message: "Unnamed control".into(),
783+
range: vec![range],
784+
err_no: ErrNo::cfc__unnamed_control,
785+
}
786+
}
771787
}
772788

773789
#[cfg(test)]

compiler/plc_diagnostics/src/errno.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ pub enum ErrNo {
9595
cfc__unconnected_source,
9696
cfc__cyclic_connection,
9797
cfc__no_associated_connector,
98+
cfc__unnamed_control,
9899
}
99100

100101
impl Display for ErrNo {

compiler/plc_driver/src/lib.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ use std::{
1717

1818
use ast::provider::IdProvider;
1919
use cli::{CompileParameters, ParameterError};
20-
use plc::{output::FormatOption, DebugLevel, ErrorFormat, OptimizationLevel, Threads};
20+
use pipelines::AnnotatedProject;
21+
use plc::{
22+
codegen::CodegenContext, output::FormatOption, DebugLevel, ErrorFormat, OptimizationLevel, Threads,
23+
};
24+
2125
use plc_diagnostics::{diagnostician::Diagnostician, diagnostics::Diagnostic};
2226
use project::project::{LibraryInformation, Project};
2327
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
@@ -193,6 +197,38 @@ pub fn compile<T: AsRef<str> + AsRef<OsStr> + Debug>(args: &[T]) -> Result<(), C
193197
Ok(())
194198
}
195199

200+
/// Parses and annotates a given project. Can be used in tests or api calls
201+
pub fn parse_and_annotate<T: SourceContainer>(
202+
name: &str,
203+
src: Vec<T>,
204+
) -> Result<AnnotatedProject, Diagnostic> {
205+
// Parse the source to ast
206+
let project = Project::new(name.to_string()).with_sources(src);
207+
let id_provider = IdProvider::default();
208+
let mut diagnostician = Diagnostician::default();
209+
pipelines::ParsedProject::parse(&project, None, id_provider.clone(), &mut diagnostician)?
210+
// Create an index, add builtins
211+
.index(id_provider.clone())?
212+
// Resolve
213+
.annotate(id_provider, &diagnostician)
214+
}
215+
216+
/// Generates an IR string from a list of sources. Useful for tests or api calls
217+
pub fn generate_to_string<T: SourceContainer>(name: &str, src: Vec<T>) -> Result<String, Diagnostic> {
218+
let mut diagnostician = Diagnostician::default();
219+
let project = parse_and_annotate(name, src)?;
220+
//Validate
221+
project.validate(&mut diagnostician)?;
222+
// Generate
223+
let context = CodegenContext::create();
224+
let module = project.generate_single_module(&context, &CompileOptions::default())?;
225+
226+
module.map(|it| it.persist_to_string()).ok_or_else(|| Diagnostic::GeneralError {
227+
message: "Cannot generate module".to_string(),
228+
err_no: plc_diagnostics::errno::ErrNo::general__err,
229+
})
230+
}
231+
196232
fn generate(
197233
location: Option<PathBuf>,
198234
compile_parameters: CompileParameters,

compiler/plc_driver/src/pipelines.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,8 @@ impl IndexedProject {
187187
/// A project that has been annotated with information about different types and used units
188188
pub struct AnnotatedProject {
189189
pub units: Vec<(CompilationUnit, IndexSet<Dependency>, StringLiterals)>,
190-
index: Index,
191-
annotations: AstAnnotations,
190+
pub index: Index,
191+
pub annotations: AstAnnotations,
192192
}
193193

194194
impl AnnotatedProject {
@@ -303,7 +303,7 @@ impl AnnotatedProject {
303303
)
304304
.map(Into::into)?;
305305

306-
result.push(GeneratedProject { target, objects: vec![obj] });
306+
result.push(GeneratedProject { target: target.clone(), objects: vec![obj] });
307307
}
308308

309309
Ok(result)
@@ -363,7 +363,7 @@ impl AnnotatedProject {
363363
})
364364
.collect::<Result<Vec<_>, Diagnostic>>()?;
365365

366-
Ok(GeneratedProject { target, objects })
366+
Ok(GeneratedProject { target: target.clone(), objects })
367367
})
368368
.collect::<Result<Vec<_>, Diagnostic>>()?;
369369

@@ -398,12 +398,12 @@ fn ensure_compile_dirs(targets: &[Target], compile_directory: &Path) -> Result<(
398398
/// A project that has been transformed into a binary representation
399399
/// Can be linked to generate a usable application
400400
#[derive(Debug)]
401-
pub struct GeneratedProject<'ctx> {
402-
target: &'ctx Target,
401+
pub struct GeneratedProject {
402+
target: Target,
403403
objects: Vec<Object>,
404404
}
405405

406-
impl GeneratedProject<'_> {
406+
impl GeneratedProject {
407407
pub fn link(
408408
&self,
409409
objects: &[Object],
@@ -504,7 +504,7 @@ impl GeneratedProject<'_> {
504504
}
505505
}?;
506506

507-
let output: Object = Object::from(output_location).with_target(&self.target.clone());
507+
let output: Object = Object::from(output_location).with_target(&self.target);
508508
Ok(output)
509509
}
510510
}

compiler/plc_xml/src/serializer.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,9 @@ declare_type_and_extend_if_needed! {
221221
(XOutVariable, with_out_variable),
222222
(XContinuation, with_continuation),
223223
(XConnector, with_connector),
224-
(XReturn, with_return)
224+
(XReturn, with_return),
225+
(XJump, with_jump),
226+
(XLabel, with_label)
225227
),
226228
(
227229
XVariable, "variable",
@@ -294,6 +296,12 @@ declare_type_and_extend_if_needed! {
294296
(XConnectionPointIn, with_connection_point_in),
295297
(XAddData, with_add_data)
296298
),
299+
(
300+
XJump, "jump",
301+
(XConnectionPointIn, with_connection_point_in),
302+
(XAddData, with_add_data)
303+
),
304+
(XLabel, "label",),
297305
(
298306
XNegated, "negated",
299307
),

0 commit comments

Comments
 (0)