use crate::errors::*;
use crate::recognizer::Recognizer;
use dmntk_model::dmntk_feel_parser::dmntk_feel::dmntk_common::Result;
use dmntk_model::model::{AnnotationEntry, DecisionRule, DecisionTable, HitPolicy, InputClause, InputEntry, OutputClause, OutputEntry, RuleAnnotationClause};
struct Size {
input_clauses_count: usize,
input_values_count: usize,
output_clauses_count: usize,
output_components_count: usize,
output_values_count: usize,
annotation_clauses_count: usize,
rule_count: usize,
}
fn size_err(details: &str) -> Result<Size> {
Err(invalid_size(details))
}
fn validate_size(recognizer: &Recognizer) -> Result<Size> {
let input_clauses_count = recognizer.input_clause_count;
if input_clauses_count == 0 {
return size_err("decision table must have minimum one input clause");
}
let input_expression_count = recognizer.input_expressions.len();
if input_expression_count != input_clauses_count {
return size_err(&format!(
"number of input expressions ({}) must be equal to the number of input clauses ({})",
input_expression_count, input_clauses_count
));
}
let input_values_count = recognizer.input_values.len();
if input_values_count > 0 && input_values_count != input_clauses_count {
return size_err(&format!(
"number of input values ({}) must be equal to the number of input clauses ({})",
input_values_count, input_clauses_count
));
}
let output_clauses_count = recognizer.output_clause_count;
if output_clauses_count == 0 {
return size_err("decision table must have minimum one output clause");
}
let output_components_count = recognizer.output_components.len();
if output_clauses_count > 1 {
if output_components_count != output_clauses_count {
return size_err(&format!(
"number of output components ({}) must be equal to the number of output clauses ({})",
output_components_count, output_clauses_count
));
}
} else if output_components_count != 0 {
return size_err("number of output components must be zero");
}
let output_values_count = recognizer.output_values.len();
if output_values_count > 0 && output_values_count != output_clauses_count {
return size_err(&format!(
"number of output values ({}) must be equal to the number of output clauses ({})",
output_values_count, output_clauses_count
));
}
let rule_count = recognizer.rule_count;
if rule_count == 0 {
return size_err("decision table must contain minimum one rule");
}
let input_entries_row_count = recognizer.input_entries.len();
if input_entries_row_count != rule_count {
return size_err(&format!(
"number of input entries ({}) must be equal to the number of rules ({})",
input_entries_row_count, rule_count
));
}
for (row_index, row) in recognizer.input_entries.iter().enumerate() {
if row.len() != input_clauses_count {
return size_err(&format!(
"number of input entries ({}) must be equal to the number of input clauses ({}) in row {}",
row.len(),
input_clauses_count,
row_index
));
}
}
let output_entries_row_count = recognizer.output_entries.len();
if output_entries_row_count != rule_count {
return size_err(&format!(
"number of output entries ({}) must be equal to the number of rules ({})",
output_entries_row_count, rule_count
));
}
for (row_index, row) in recognizer.output_entries.iter().enumerate() {
if row.len() != output_clauses_count {
return size_err(&format!(
"number of output entries ({}) must be equal to the number of output clauses ({}) in row {}",
row.len(),
output_clauses_count,
row_index
));
}
}
let annotation_clauses_count = recognizer.annotation_clause_count;
if annotation_clauses_count > 0 {
let annotation_entries_row_count = recognizer.annotation_entries.len();
if annotation_entries_row_count != rule_count {
return size_err(&format!(
"number of annotation entries ({}) must be equal to the number of rules ({})",
annotation_entries_row_count, rule_count
));
}
for (row_index, row) in recognizer.annotation_entries.iter().enumerate() {
if row.len() != annotation_clauses_count {
return size_err(&format!(
"number of annotation entries ({}) must be equal to the number of annotation clauses ({}) in row {}",
row.len(),
annotation_clauses_count,
row_index
));
}
}
}
Ok(Size {
input_clauses_count,
input_values_count,
output_clauses_count,
output_components_count,
output_values_count,
annotation_clauses_count,
rule_count,
})
}
pub fn build(text: &str) -> Result<DecisionTable> {
let recognizer = Recognizer::recognize(text)?;
let size = validate_size(&recognizer)?;
let information_item_name = recognizer.information_item_name.clone();
let hit_policy = recognizer.hit_policy;
let aggregation;
if let HitPolicy::Collect(built_in_aggregator) = hit_policy {
aggregation = Some(built_in_aggregator)
} else {
aggregation = None
}
let preferred_orientation = recognizer.orientation;
let output_label = recognizer.output_label.clone();
let mut inputs = vec![];
for i in 0..size.input_clauses_count {
inputs.push(InputClause {
input_expression: recognizer.input_expressions[i].clone(),
input_values: if size.input_values_count > 0 {
Some(recognizer.input_values[i].clone())
} else {
None
},
});
}
let mut outputs = vec![];
for i in 0..size.output_clauses_count {
outputs.push(OutputClause {
type_ref: None,
name: if size.output_components_count > 0 {
Some(recognizer.output_components[i].clone())
} else {
None
},
output_values: if size.output_values_count > 0 {
Some(recognizer.output_values[i].clone())
} else {
None
},
default_output_entry: None,
});
}
let mut annotations = vec![];
for i in 0..recognizer.annotation_clause_count {
annotations.push(RuleAnnotationClause {
name: recognizer.annotations[i].clone(),
});
}
let mut rules = vec![];
for rule_index in 0..size.rule_count {
let mut input_entries = vec![];
for column_index in 0..size.input_clauses_count {
let input_entry = InputEntry {
text: recognizer.input_entries[rule_index][column_index].clone(),
};
input_entries.push(input_entry);
}
let mut output_entries = vec![];
for column_index in 0..size.output_clauses_count {
let output_entry = OutputEntry {
text: recognizer.output_entries[rule_index][column_index].clone(),
};
output_entries.push(output_entry);
}
let mut annotation_entries = vec![];
for column_index in 0..size.annotation_clauses_count {
let annotation_entry = AnnotationEntry {
text: recognizer.annotation_entries[rule_index][column_index].clone(),
};
annotation_entries.push(annotation_entry);
}
rules.push(DecisionRule {
input_entries,
output_entries,
annotation_entries,
});
}
let decision_table = DecisionTable {
information_item_name,
input_clauses: inputs,
output_clauses: outputs,
annotations,
rules,
hit_policy,
aggregation,
preferred_orientation,
output_label,
};
Ok(decision_table)
}