Skip to content

Commit

Permalink
Feature/display name attributes (#565)
Browse files Browse the repository at this point in the history
Implements rule attributes
  • Loading branch information
aannleax authored Jan 7, 2025
2 parents 4a892be + f9e16d1 commit fdc094b
Show file tree
Hide file tree
Showing 9 changed files with 291 additions and 22 deletions.
17 changes: 5 additions & 12 deletions nemo/src/execution/tracing/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,24 +207,17 @@ pub struct TraceTreeRuleApplication {
}

impl TraceTreeRuleApplication {
/// Instantiate the given rule with its assignment producing a [Rule] with only ground terms.
fn to_instantiated_rule(&self) -> Rule {
let mut rule = self.rule.clone();
self.assignment.apply(&mut rule);

rule
}

/// Get the [Fact] that was produced by this rule application.
fn to_derived_atom(&self) -> Fact {
let rule = self.to_instantiated_rule();
let derived_atom = rule.head()[self._position].clone();
Fact::from(derived_atom)
let mut fact = self.rule.head()[self._position].clone();
self.assignment.apply(&mut fact);

Fact::from(fact)
}

/// Get a string representation of the Instantiated rule.
fn to_instantiated_string(&self) -> String {
self.to_instantiated_rule().to_string()
self.rule.display_instantiated(&self.assignment)
}
}

Expand Down
77 changes: 72 additions & 5 deletions nemo/src/rule_model/components/rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use std::{collections::HashSet, fmt::Display, hash::Hash};

use nemo_physical::datavalues::DataValue;

use crate::{
parse_component,
parser::ast::ProgramAST,
Expand All @@ -11,6 +13,7 @@ use crate::{
ValidationErrorBuilder,
},
origin::Origin,
substitution::Substitution,
translation::ASTProgramTranslation,
},
};
Expand Down Expand Up @@ -39,6 +42,8 @@ pub struct Rule {

/// Name of the rule
name: Option<String>,
/// How an instantiated version of this rule should be displayed
display: Option<Term>,

/// Head of the rule
head: Vec<Atom>,
Expand All @@ -57,6 +62,7 @@ impl Rule {
Self {
origin: Origin::Created,
name: None,
display: None,
head,
body,
}
Expand All @@ -68,6 +74,38 @@ impl Rule {
self
}

/// Set how an instantiated version of the rule should be displayed.
pub fn set_display(mut self, display: Term) -> Self {
self.display = Some(display);
self
}

/// Return a string representation of the rule instantiated with the given [Substitution].
/// This will either return
/// * The content of the display attribute for this rule
/// * a canonical string representation of the rule (i.e. [Display] representation)
/// whichever is the first defined in this list.
pub fn display_instantiated(&self, substitution: &Substitution) -> String {
if let Some(mut display) = self.display.clone() {
substitution.apply(&mut display);
if let Term::Primitive(Primitive::Ground(ground)) = display.reduce() {
if let Some(result) = ground.value().to_plain_string() {
return result;
}
}
}

let mut rule_name_prefix = String::from("");
if let Some(name) = &self.name {
rule_name_prefix = format!("{}: ", name.clone());
}

let mut rule_instantiated = self.clone();
substitution.apply(&mut rule_instantiated);

format!("{}{}", rule_name_prefix, rule_instantiated)
}

/// Return a reference to the body of the rule.
pub fn body(&self) -> &Vec<Literal> {
&self.body
Expand Down Expand Up @@ -352,6 +390,22 @@ impl ProgramComponent for Rule {
.flat_map(|atom| atom.variables())
.any(|variable| variable.is_existential());

if let Some(display) = &self.display {
display.validate(builder)?;

for variable in display.variables() {
if !safe_variables.contains(variable) {
builder.report_error(
*variable.origin(),
ValidationErrorKind::AttributeRuleUnsafe {
variable: variable.to_string(),
},
);
return None;
}
}
}

for atom in self.head() {
atom.validate(builder)?;

Expand Down Expand Up @@ -520,6 +574,8 @@ pub struct RuleBuilder {

/// Name of the rule
name: Option<String>,
/// How an instantiated version of this rule should be displayed
display: Option<Term>,

/// Head of the rule
head: Vec<Atom>,
Expand All @@ -529,11 +585,17 @@ pub struct RuleBuilder {

impl RuleBuilder {
/// Set the name of the built rule.
pub fn name(mut self, name: &str) -> Self {
pub fn name_mut(&mut self, name: &str) -> &mut Self {
self.name = Some(name.to_string());
self
}

/// Set the display property of the built rule.
pub fn display_mut(&mut self, display: Term) -> &mut Self {
self.display = Some(display);
self
}

/// Set the [Origin] of the built rule.
pub fn origin(mut self, origin: Origin) -> Self {
self.origin = origin;
Expand Down Expand Up @@ -602,11 +664,16 @@ impl RuleBuilder {

/// Finish building and return a [Rule].
pub fn finalize(self) -> Rule {
let rule = Rule::new(self.head, self.body).set_origin(self.origin);
let mut rule = Rule::new(self.head, self.body).set_origin(self.origin);

match &self.name {
Some(name) => rule.set_name(name),
None => rule,
if let Some(name) = &self.name {
rule = rule.set_name(name);
}

if let Some(display) = self.display {
rule = rule.set_display(display);
}

rule
}
}
10 changes: 8 additions & 2 deletions nemo/src/rule_model/components/term/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,11 @@ impl Operation {
&HashMap::default(),
None,
);
let result = stack_program.evaluate_data(&[]).expect("term is ground");

Term::from(GroundTerm::new(result))
match stack_program.evaluate_data(&[]) {
Some(result) => Term::from(GroundTerm::new(result)),
None => Term::Operation(self.clone()),
}
}
}

Expand Down Expand Up @@ -175,6 +177,10 @@ impl Operation {
OperationKind::NumericDivision => "/",
OperationKind::Equal => "=",
OperationKind::Unequals => "!=",
OperationKind::NumericGreaterthan => ">",
OperationKind::NumericGreaterthaneq => ">=",
OperationKind::NumericLessthan => "<",
OperationKind::NumericLessthaneq => "<=",
_ => return None,
})
}
Expand Down
13 changes: 12 additions & 1 deletion nemo/src/rule_model/error/hint/similar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
use similar_string::find_best_similarity;
use strum::IntoEnumIterator;

use crate::rule_model::components::term::operation::operation_kind::OperationKind;
use crate::rule_model::{
components::term::operation::operation_kind::OperationKind,
translation::attribute::KnownAttributes,
};

use super::Hint;

Expand Down Expand Up @@ -46,4 +49,12 @@ impl Hint {

Self::similar("operation", target, options)
}

/// Checks whether a similar string exists within the known attributes
/// and returns the most similar one, if it meets the threshold.
pub fn similar_attribute(target: impl AsRef<str>) -> Option<Self> {
let options = KnownAttributes::iter().map(|kind| kind.name());

Self::similar("attribute", target, options)
}
}
24 changes: 24 additions & 0 deletions nemo/src/rule_model/error/translation_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,30 @@ pub enum TranslationErrorKind {
#[assoc(note = "rdf imports/exports must have file extension nt, nq, ttl, trig, or rdf.")]
#[assoc(code = 118)]
RdfUnspecifiedUnknownExtension(String),
/// Unkown attribute
#[error("unknown attribute: `{0}`")]
#[assoc(code = 119)]
AttributeUnknown(String),
/// Unexpected attribute
#[error("unexpected attribute: `{0}`")]
#[assoc(code = 120)]
AttributeUnexpected(String),
/// Attributed defined multiple times
#[error("")]
#[assoc(code = 121)]
AttributeRedefined,
/// Attribute contains wrong number of parameters
#[error("attribute expected {expected} parameters, found {found}")]
#[assoc(code = 122)]
AttributeInvalidParameterCount { expected: usize, found: usize },
/// Invalid attribute parameter: Wrong type
#[error("attribute parameter of type {found}, expected {expected}")]
#[assoc(code = 123)]
AttributeParameterWrongType { expected: String, found: String },
/// Invalid attribute parameter: Wrong component
#[error("attribute parameter is {found}, expected {expected}")]
#[assoc(code = 124)]
AttributeParameterWrongComponent { expected: String, found: String },

/// Unsupported: Declare statements
#[error(r#"declare statements are currently unsupported"#)]
Expand Down
4 changes: 4 additions & 0 deletions nemo/src/rule_model/error/validation_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ pub enum ValidationErrorKind {
#[error(r#"unknown compression format `{format}`"#)]
#[assoc(code = 226)]
ImportExportUnknownCompression { format: String },
/// Attribute in rule is unsafe
#[error(r#"display attribute uses unsafe variable: `{variable}`"#)]
#[assoc(code = 227)]
AttributeRuleUnsafe { variable: String },

/// Unsupported feature: Multiple aggregates in one rule
#[error(r#"multiple aggregates in one rule is currently unsupported"#)]
Expand Down
1 change: 1 addition & 0 deletions nemo/src/rule_model/translation.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! This module defines [ASTProgramTranslation].
pub(crate) mod attribute;
pub(crate) mod basic;
pub(crate) mod complex;
pub(crate) mod directive;
Expand Down
Loading

0 comments on commit fdc094b

Please sign in to comment.