Skip to content

Commit

Permalink
feat(cfc): Sink/source connections (PLC-lang#956)
Browse files Browse the repository at this point in the history
* add sink-source connection-mark desugaring

* Add tests for the desugaring functionality

* refactor: Change the desugaring algorithm to be simpler

* refactor: change requests

---------
Co-authored-by: Ghaith Hachem <[email protected]>
  • Loading branch information
mhasel authored Sep 20, 2023
1 parent 12b8226 commit d6e68cf
Show file tree
Hide file tree
Showing 68 changed files with 3,135 additions and 483 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ serde_json = "1"
toml = "0.5"
lazy_static = "1.4.0"
shell-words = "1.1.0"
itertools = "0.11"
plc_derive = { path = "./compiler/plc_derive" }
lld_rs = "140.0.0"
which = "4.2.5"
log.workspace = true
inkwell.workspace = true
chrono.workspace = true
itertools.workspace = true

[dev-dependencies]
num = "0.4"
Expand Down Expand Up @@ -77,3 +77,4 @@ encoding_rs = "0.8"
encoding_rs_io = "0.1"
log = "0.4"
chrono = { version = "0.4", default-features = false }
itertools = "0.11"
24 changes: 24 additions & 0 deletions compiler/plc_diagnostics/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,30 @@ impl Diagnostic {
err_no: ErrNo::cfc__unexpected_node,
}
}

pub fn unconnected_source(connector_name: &str, range: SourceLocation) -> Diagnostic {
Diagnostic::SemanticError {
message: format!("Source '{connector_name}' is not connected."),
range: vec![range],
err_no: ErrNo::cfc__unconnected_source,
}
}

pub fn sink_without_associated_source(connector_name: &str, range: SourceLocation) -> Diagnostic {
Diagnostic::SemanticError {
message: format!("Expected a corresponding source-connection mark for sink '{connector_name}', but could not find one."),
range: vec![range],
err_no: ErrNo::cfc__no_associated_connector,
}
}

pub fn cyclic_connection(message: String, range: SourceLocation) -> Diagnostic {
Diagnostic::SemanticError {
message: format!("Sink is connected to itself. Found the following recursion: {message}"),
range: vec![range],
err_no: ErrNo::cfc__cyclic_connection,
}
}
}

#[cfg(test)]
Expand Down
3 changes: 3 additions & 0 deletions compiler/plc_diagnostics/src/errno.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ pub enum ErrNo {
cfc__empty_control_statement,
cfc__undefined_node,
cfc__unexpected_node,
cfc__unconnected_source,
cfc__cyclic_connection,
cfc__no_associated_connector,
}

impl Display for ErrNo {
Expand Down
1 change: 1 addition & 0 deletions compiler/plc_xml/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ plc = { path = "../..", package = "rusty" }
ast = { path = "../plc_ast/", package = "plc_ast" }
plc_diagnostics = { path = "../plc_diagnostics" }
plc_source = { path = "../plc_source" }
itertools.workspace = true

[features]
default = []
Expand Down
8 changes: 5 additions & 3 deletions compiler/plc_xml/src/model/action.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::borrow::Cow;

#[derive(Debug)]
pub(crate) struct Action {
pub name: String,
pub type_name: String,
pub(crate) struct Action<'xml> {
pub name: Cow<'xml, str>,
pub type_name: Cow<'xml, str>,
}
18 changes: 9 additions & 9 deletions compiler/plc_xml/src/model/block.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
use std::collections::HashMap;
use std::{borrow::Cow, collections::HashMap};

use quick_xml::events::Event;

use crate::{error::Error, extensions::GetOrErr, reader::PeekableReader, xml_parser::Parseable};

use super::variables::BlockVariable;

#[derive(Debug, PartialEq)]
pub(crate) struct Block {
#[derive(Debug, PartialEq, Eq, Hash)]
pub(crate) struct Block<'xml> {
pub local_id: usize,
pub type_name: String,
pub instance_name: Option<String>,
pub type_name: Cow<'xml, str>,
pub instance_name: Option<Cow<'xml, str>>,
pub execution_order_id: Option<usize>,
pub variables: Vec<BlockVariable>,
}

impl Block {
impl<'xml> Block<'xml> {
pub fn new(mut hm: HashMap<String, String>, variables: Vec<BlockVariable>) -> Result<Self, Error> {
Ok(Self {
local_id: hm.get_or_err("localId").map(|it| it.parse())??,
type_name: hm.get_or_err("typeName")?,
instance_name: hm.remove("instanceName"),
type_name: Cow::from(hm.get_or_err("typeName")?),
instance_name: hm.remove("instanceName").map(Cow::from),
execution_order_id: hm.get("executionOrderId").map(|it| it.parse()).transpose()?,
variables,
})
}
}

impl Parseable for Block {
impl<'xml> Parseable for Block<'xml> {
type Item = Self;

fn visit(reader: &mut PeekableReader) -> Result<Self::Item, Error> {
Expand Down
10 changes: 5 additions & 5 deletions compiler/plc_xml/src/model/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ use super::fbd::FunctionBlockDiagram;
use crate::{error::Error, reader::PeekableReader, xml_parser::Parseable};

#[derive(Debug, Default)]
pub(crate) struct Body {
pub function_block_diagram: Option<FunctionBlockDiagram>,
pub(crate) struct Body<'xml> {
pub function_block_diagram: Option<FunctionBlockDiagram<'xml>>,
}

impl Body {
fn new(fbd: Option<FunctionBlockDiagram>) -> Result<Self, Error> {
impl<'xml> Body<'xml> {
fn new(fbd: Option<FunctionBlockDiagram<'xml>>) -> Result<Self, Error> {
Ok(Self { function_block_diagram: fbd })
}

Expand All @@ -18,7 +18,7 @@ impl Body {
}
}

impl Parseable for Body {
impl<'xml> Parseable for Body<'xml> {
type Item = Self;

fn visit(reader: &mut PeekableReader) -> Result<Self::Item, Error> {
Expand Down
24 changes: 12 additions & 12 deletions compiler/plc_xml/src/model/connector.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::{borrow::Cow, collections::HashMap};

use quick_xml::events::Event;

Expand All @@ -9,42 +9,42 @@ use crate::{
xml_parser::Parseable,
};

#[derive(Debug, PartialEq)]
pub(crate) struct Connector {
#[derive(Debug, PartialEq, Eq, Hash)]
pub(crate) struct Connector<'xml> {
pub kind: ConnectorKind,
pub name: String,
pub name: Cow<'xml, str>,
pub local_id: usize,
pub ref_local_id: Option<usize>,
pub formal_parameter: Option<String>,
pub formal_parameter: Option<Cow<'xml, str>>,
}

impl Connector {
impl<'xml> Connector<'xml> {
pub fn new(mut hm: HashMap<String, String>, kind: ConnectorKind) -> Result<Self, Error> {
Ok(Self {
kind,
name: hm.get_or_err("name")?,
name: Cow::from(hm.get_or_err("name")?),
local_id: hm.get_or_err("localId").map(|it| it.parse())??,
ref_local_id: hm.get("refLocalId").map(|it| it.parse()).transpose()?,
formal_parameter: hm.remove("formalParameter"),
formal_parameter: hm.remove("formalParameter").map(Cow::from),
})
}
}

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub(crate) enum ConnectorKind {
Source,
Sink,
}

impl Parseable for Connector {
impl<'xml> Parseable for Connector<'xml> {
type Item = Self;

fn visit(reader: &mut PeekableReader) -> Result<Self::Item, Error> {
let next = reader.peek()?;
let kind = match &next {
Event::Start(tag) | Event::Empty(tag) => match tag.name().as_ref() {
b"connector" => ConnectorKind::Sink,
b"continuation" => ConnectorKind::Source,
b"connector" => ConnectorKind::Source,
b"continuation" => ConnectorKind::Sink,
_ => return Err(Error::UnexpectedElement(tag.name().try_to_string()?)),
},

Expand Down
16 changes: 8 additions & 8 deletions compiler/plc_xml/src/model/control.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{collections::HashMap, str::FromStr};
use std::{borrow::Cow, collections::HashMap, str::FromStr};

use quick_xml::events::Event;

Expand All @@ -9,21 +9,21 @@ use crate::{
xml_parser::Parseable,
};

#[derive(Debug, PartialEq)]
pub(crate) struct Control {
#[derive(Debug, PartialEq, Eq, Hash)]
pub(crate) struct Control<'xml> {
pub kind: ControlKind,
pub name: Option<String>,
pub name: Option<Cow<'xml, str>>,
pub local_id: usize,
pub ref_local_id: Option<usize>,
pub execution_order_id: Option<usize>,
pub negated: bool,
}

impl Control {
impl<'xml> Control<'xml> {
pub fn new(mut hm: HashMap<String, String>, kind: ControlKind) -> Result<Self, Error> {
Ok(Self {
kind,
name: hm.remove("label"),
name: hm.remove("label").map(Cow::from),
local_id: hm.get_or_err("localId").map(|it| it.parse())??,
ref_local_id: hm.get("refLocalId").map(|it| it.parse()).transpose()?,
execution_order_id: hm.get("executionOrderId").map(|it| it.parse()).transpose()?,
Expand All @@ -32,7 +32,7 @@ impl Control {
}
}

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone, Eq, Hash, Copy)]
pub(crate) enum ControlKind {
Jump,
Label,
Expand All @@ -52,7 +52,7 @@ impl FromStr for ControlKind {
}
}

impl Parseable for Control {
impl<'xml> Parseable for Control<'xml> {
type Item = Self;

fn visit(reader: &mut PeekableReader) -> Result<Self::Item, Error> {
Expand Down
Loading

0 comments on commit d6e68cf

Please sign in to comment.