Skip to content

Commit

Permalink
refactor: some progress
Browse files Browse the repository at this point in the history
  • Loading branch information
Lukáš Chudíček committed Dec 3, 2023
1 parent 36f6e5a commit 0c908f7
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod test_utils; // TODO:
// to have it accessible from outside binaries.
mod expression_components;
mod symbolic_domains;
mod system;
mod xml_parsing;

#[cfg(test)]
Expand Down
26 changes: 26 additions & 0 deletions src/system.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
pub mod variable_update_function {
use crate::expression_components::expression::Expression;

pub struct VariableUpdateFn<T> {
// pub input_vars_names: Vec<String>, // todo what for? remove by default if not needed; uncomment if needed
// pub target_var_name: String, // todo this should not care about this; the caller should keep this information
pub terms: Vec<(T, Expression<T>)>,
pub default: T,
}

impl<T> VariableUpdateFn<T> {
pub fn new(
// input_vars_names: Vec<String>,
// target_var_name: String,
terms: Vec<(T, Expression<T>)>,
default: T,
) -> Self {
Self {
// input_vars_names,
// target_var_name,
terms,
default,
}
}
}
}
1 change: 1 addition & 0 deletions src/xml_parsing/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod expression_parser;
pub mod utils;
pub mod variable_update_fn_parser;
pub mod xml_reader;
2 changes: 2 additions & 0 deletions src/xml_parsing/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub enum XmlReadingError {
},
UnderlyingReaderError(#[from] xml::reader::Error),
ParsingError(String),
NoSuchAttribute(String),
}

impl Display for XmlReadingError {
Expand All @@ -39,6 +40,7 @@ impl Display for XmlReadingError {
write!(f, "Underlying reader error: {}", e)
}
XmlReadingError::ParsingError(s) => write!(f, "Parsing error; could not parse {}", s),
XmlReadingError::NoSuchAttribute(s) => write!(f, "No such attribute: {}", s),
}
}
}
Expand Down
185 changes: 185 additions & 0 deletions src/xml_parsing/variable_update_fn_parser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
use std::{io::BufRead, str::FromStr};

use xml::reader::XmlEvent;

use crate::{
expression_components::expression::Expression,
system::variable_update_function::VariableUpdateFn,
};

use super::{
utils::expect_opening,
utils::{expect_closure_of, expect_opening_of, map_list, StartElementWrapper, XmlReadingError},
xml_reader::XmlReader,
};

/// expects the xml reader to be at the start of the <transition> element
impl<T: FromStr> VariableUpdateFn<T> {
pub fn try_from_xml<XR: XmlReader<BR>, BR: BufRead>(
xml: &mut XR,
) -> Result<Self, XmlReadingError> {
let some_start_element = expect_opening(xml)?;
if !matches!(
some_start_element.name.local_name.as_str(),
"listOfInputs" | "listOfOutputs"
) {
return Err(XmlReadingError::UnexpectedEvent {
expected: super::utils::ExpectedXmlEvent::Start(
"listOfInputs or listOfOutputs".to_string(),
),
got: XmlEvent::StartElement {
name: some_start_element.name,
attributes: some_start_element.attributes,
namespace: some_start_element.namespace,
},
});
}

// listOfInputs might not be present at all
let input_vars_names = if some_start_element.name.local_name == "listOfInputs" {
let aux = map_list(xml, "listOfInputs", "input", process_input_var_name_item)?;
expect_closure_of(xml, "listOfOutputs")?; // must be followed by listOfOutputs
aux
} else {
Vec::new()
};

// listOfOutputs must be present
let target_vars_names =
map_list(xml, "listOfOutputs", "output", process_output_var_name_item)?;
let mut target_vars_names = target_vars_names.iter();
let head = target_vars_names // todo head must be used; caller has no way of knowing which variable is the target otherwise
.next()
.ok_or(XmlReadingError::UnexpectedEvent {
expected: super::utils::ExpectedXmlEvent::Start("target var name".to_string()),
got: XmlEvent::EndElement {
name: some_start_element.name,
},
});
target_vars_names.next().map_or_else(
|| Ok::<(), ()>(()),
|_elem| {
// Err(XmlReadingError::UnexpectedEvent {
// expected: super::utils::ExpectedXmlEvent::End("list of vars names".to_string()),
// got: // ...,
// })
panic!("expected only one target var but found multiple; todo might want to change this")
},
);
// .ok_or(XmlReadingError::UnexpectedEvent { expected: super::utils::ExpectedXmlEvent::End("listOfOutputs".to_string()), got: () })

expect_opening_of(xml, "listOfFunctionTerms")?;
let (default, terms) = get_default_and_list_of_terms(xml)?;

expect_closure_of(xml, "transition")?;
// Ok(Self::new(input_vars_names, head.into(), terms, default))
// Ok(VariableUpdateFn::new(terms, default))

let xd = VariableUpdateFn::new(terms, default);

Ok(xd)
}
}

fn process_input_var_name_item<XR: XmlReader<BR>, BR: BufRead>(
xml: &mut XR,
current: StartElementWrapper,
) -> Result<String, XmlReadingError> {
let mut qualitative_species = current.attributes.iter().filter_map(|att| {
if att.name.local_name == "qualitativeSpecies" {
Some(att.value.clone())
} else {
None
}
});

let item = qualitative_species
.next()
// .ok_or("expected \"qualitativeSpecies\" arg in input, but none found")?;
.ok_or(XmlReadingError::NoSuchAttribute(
"qualitativeSpecies".to_string(),
))?; // todo

expect_closure_of(xml, "input")?;

Ok(item)
}

fn process_output_var_name_item<XR: XmlReader<BR>, BR: BufRead>(
xml: &mut XR,
current: StartElementWrapper,
) -> Result<String, XmlReadingError> {
let mut qualitative_species = current.attributes.iter().filter_map(|att| {
if att.name.local_name == "qualitativeSpecies" {
Some(att.value.clone())
} else {
None
}
});

let item = qualitative_species
.next()
.ok_or(XmlReadingError::NoSuchAttribute(
"value after qualitativeSpecies".to_string(),
))?;

expect_closure_of(xml, "output")?;

Ok(item)
}

type Out<T> = (T, Vec<(T, Expression<T>)>);

fn get_default_and_list_of_terms<T: FromStr, XR: XmlReader<BR>, BR: BufRead>(
xml: &mut XR,
) -> Result<Out<T>, XmlReadingError> {
// firs should be the default
let default_element = expect_opening_of(xml, "defaultTerm")?;

let default_val = result_level_from_attributes(&default_element)?;

expect_closure_of(xml, "defaultTerm")?;

// expect_opening_of("functionTerms", xml)?; // already inside "functionTerms" List; first item was default element
let values_and_expressions = map_list(
xml,
"listOfFunctionTerms",
"functionTerm",
process_function_term_item,
)?;

Ok((default_val, values_and_expressions))
}

fn process_function_term_item<T: FromStr, XR: XmlReader<BR>, BR: BufRead>(
xml: &mut XR,
current: StartElementWrapper,
) -> Result<(T, Expression<T>), XmlReadingError> {
let res_lvl = result_level_from_attributes(&current)?;

expect_opening_of(xml, "math")?;
// try_from_xml expects to have the first apply already opened
expect_opening_of(xml, "apply")?;

let exp = Expression::try_from_xml(xml)?;

expect_closure_of(xml, "math")?;
expect_closure_of(xml, "functionTerm")?;

Ok((res_lvl, exp))
}

fn result_level_from_attributes<T: FromStr>(
elem: &StartElementWrapper,
) -> Result<T, XmlReadingError> {
let attribute_with_result_lvl = elem
.attributes
.iter()
.find(|attr_name| attr_name.name.local_name == "resultLevel")
.ok_or(XmlReadingError::NoSuchAttribute("resultLevel".to_string()))?;

attribute_with_result_lvl
.value
.parse::<T>()
.map_err(|_| XmlReadingError::ParsingError(attribute_with_result_lvl.value))
}

0 comments on commit 0c908f7

Please sign in to comment.