From 3530364ea8c8a5fcd5d75d32d81d1b31a283e76c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20L=C3=BChne?= Date: Fri, 28 Feb 2020 15:35:47 +0100 Subject: [PATCH] Implement variable parsing --- src/ast.rs | 18 +-- src/error.rs | 69 +++++++++ src/lib.rs | 4 + src/parse.rs | 26 +++- src/parse/names.rs | 45 ++---- src/parse/terms.rs | 346 +++++++++++++++++++++++++++++++++++++++------ src/utils.rs | 72 ++++++++++ 7 files changed, 494 insertions(+), 86 deletions(-) create mode 100644 src/error.rs create mode 100644 src/utils.rs diff --git a/src/ast.rs b/src/ast.rs index 3c99087..aab5c08 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -174,14 +174,14 @@ pub struct Function impl Function { - pub fn new(declaration: &std::rc::Rc, arguments: Vec>) -> Self + pub fn new(declaration: std::rc::Rc, arguments: Vec>) -> Self { assert_eq!(declaration.arity, arguments.len(), "function has a different number of arguments then declared"); Self { - declaration: std::rc::Rc::clone(declaration), + declaration, arguments, } } @@ -221,11 +221,11 @@ pub struct Variable impl Variable { - pub fn new(declaration: &std::rc::Rc) -> Self + pub fn new(declaration: std::rc::Rc) -> Self { Self { - declaration: std::rc::Rc::clone(declaration), + declaration, } } } @@ -338,14 +338,14 @@ pub struct Predicate impl Predicate { - pub fn new(declaration: &std::rc::Rc, arguments: Vec>) -> Self + pub fn new(declaration: std::rc::Rc, arguments: Vec>) -> Self { assert_eq!(declaration.arity, arguments.len(), "predicate has a different number of arguments then declared"); Self { - declaration: std::rc::Rc::clone(declaration), + declaration, arguments, } } @@ -405,7 +405,7 @@ impl Term Self::boolean(false) } - pub fn function(declaration: &std::rc::Rc, arguments: Vec>) + pub fn function(declaration: std::rc::Rc, arguments: Vec>) -> Self { Self::Function(Function::new(declaration, arguments)) @@ -466,7 +466,7 @@ impl Term Self::UnaryOperation(UnaryOperation::new(operator, argument)) } - pub fn variable(declaration: &std::rc::Rc) -> Self + pub fn variable(declaration: std::rc::Rc) -> Self { Self::Variable(Variable::new(declaration)) } @@ -579,7 +579,7 @@ impl Formula Self::Or(arguments) } - pub fn predicate(declaration: &std::rc::Rc, arguments: Vec>) + pub fn predicate(declaration: std::rc::Rc, arguments: Vec>) -> Self { Self::Predicate(Predicate::new(declaration, arguments)) diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..a148ff5 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,69 @@ +pub type Source = Box; + +pub enum Kind +{ + Logic(&'static str), +} + +pub struct Error +{ + pub kind: Kind, + pub source: Option, +} + +impl Error +{ + pub(crate) fn new(kind: Kind) -> Self + { + Self + { + kind, + source: None, + } + } + + pub(crate) fn with>(mut self, source: S) -> Self + { + self.source = Some(source.into()); + self + } + + pub(crate) fn new_logic(description: &'static str) -> Self + { + Self::new(Kind::Logic(description)) + } +} + +impl std::fmt::Debug for Error +{ + fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result + { + match &self.kind + { + Kind::Logic(ref description) => write!(formatter, + "logic error, please report to bug tracker ({})", description), + }?; + + Ok(()) + } +} + +impl std::fmt::Display for Error +{ + fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result + { + write!(formatter, "{:?}", self) + } +} + +impl std::error::Error for Error +{ + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> + { + match &self.source + { + Some(source) => Some(source.as_ref()), + None => None, + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 61aef19..575c316 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,10 @@ mod ast; +mod error; pub mod format; #[cfg(feature = "parse")] pub mod parse; +mod utils; pub use ast::*; +pub use error::Error; +pub use utils::VariableDeclarationStack; diff --git a/src/parse.rs b/src/parse.rs index d9a5983..cd278a5 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -3,8 +3,30 @@ mod names; mod terms; pub(crate) use helpers::word_boundary; -pub use names::{function_name, predicate_name, variable_name}; -pub use terms::{boolean, integer, special_integer, string}; +pub use names::{function_or_predicate_name, variable_name}; +pub use terms::{boolean, function, integer, predicate, special_integer, string, variable, + variable_declaration}; + +pub struct Declarations +{ + function_declarations: std::cell::RefCell, + predicate_declarations: std::cell::RefCell, + variable_declaration_stack: std::cell::RefCell, +} + +impl Declarations +{ + pub fn new() -> Self + { + Self + { + function_declarations: std::cell::RefCell::new(crate::FunctionDeclarations::new()), + predicate_declarations: std::cell::RefCell::new(crate::PredicateDeclarations::new()), + variable_declaration_stack: + std::cell::RefCell::new(crate::VariableDeclarationStack::new()), + } + } +} /* use nom:: diff --git a/src/parse/names.rs b/src/parse/names.rs index 763cf5d..3660c12 100644 --- a/src/parse/names.rs +++ b/src/parse/names.rs @@ -28,7 +28,7 @@ fn is_variable_name_character_body(c: char) -> bool c.is_alphanumeric() || c == '_' } -pub fn function_name(i: &str) -> IResult<&str, &str> +pub fn function_or_predicate_name(i: &str) -> IResult<&str, &str> { recognize ( @@ -44,11 +44,6 @@ pub fn function_name(i: &str) -> IResult<&str, &str> )(i) } -pub fn predicate_name(i: &str) -> IResult<&str, &str> -{ - function_name(i) -} - pub fn variable_name(i: &str) -> IResult<&str, &str> { recognize @@ -71,32 +66,20 @@ mod tests use crate::parse::*; #[test] - fn parse_function_name() + fn parse_function_or_predicate_name() { - assert_eq!(function_name("f rest"), Ok((" rest", "f"))); - assert_eq!(function_name("function_123 rest"), Ok((" rest", "function_123"))); - assert!(function_name("0 rest").is_err()); - assert!(function_name("123_asd rest").is_err()); - assert!(function_name("F rest").is_err()); - assert!(function_name("Function_123 rest").is_err()); - assert!(function_name("_ rest").is_err()); - assert!(function_name("_function_123 rest").is_err()); - assert!(function_name(" ").is_err()); - } - - #[test] - fn parse_predicate_name() - { - assert_eq!(predicate_name("p rest"), Ok((" rest", "p"))); - assert_eq!(predicate_name("p, rest"), Ok((", rest", "p"))); - assert_eq!(predicate_name("predicate_123 rest"), Ok((" rest", "predicate_123"))); - assert!(predicate_name("0 rest").is_err()); - assert!(predicate_name("123_asd rest").is_err()); - assert!(predicate_name("P rest").is_err()); - assert!(predicate_name("Predicate_123 rest").is_err()); - assert!(predicate_name("_ rest").is_err()); - assert!(predicate_name("_predicate_123 rest").is_err()); - assert!(predicate_name(" ").is_err()); + assert_eq!(function_or_predicate_name("p rest"), Ok((" rest", "p"))); + assert_eq!(function_or_predicate_name("f rest"), Ok((" rest", "f"))); + assert_eq!(function_or_predicate_name("p, rest"), Ok((", rest", "p"))); + assert_eq!(function_or_predicate_name("f, rest"), Ok((", rest", "f"))); + assert_eq!(function_or_predicate_name("name_123 rest"), Ok((" rest", "name_123"))); + assert!(function_or_predicate_name("0 rest").is_err()); + assert!(function_or_predicate_name("123_asd rest").is_err()); + assert!(function_or_predicate_name("P rest").is_err()); + assert!(function_or_predicate_name("Predicate_123 rest").is_err()); + assert!(function_or_predicate_name("_ rest").is_err()); + assert!(function_or_predicate_name("_predicate_123 rest").is_err()); + assert!(function_or_predicate_name(" ").is_err()); } #[test] diff --git a/src/parse/terms.rs b/src/parse/terms.rs index b6cfee1..4bcf548 100644 --- a/src/parse/terms.rs +++ b/src/parse/terms.rs @@ -3,12 +3,13 @@ use nom:: IResult, branch::alt, bytes::complete::{escaped_transform, tag}, - character::complete::{digit1, none_of}, + character::complete::{digit1, multispace0, none_of}, combinator::{map, map_res, opt, recognize}, - sequence::{delimited, pair, terminated}, + multi::separated_list, + sequence::{delimited, pair, preceded, terminated}, }; -use super::word_boundary; +use super::{Declarations, function_or_predicate_name, word_boundary, variable_name}; fn true_(i: &str) -> IResult<&str, crate::Term> { @@ -148,61 +149,150 @@ pub fn string(i: &str) -> IResult<&str, crate::Term> )(i) } -/* -fn function<'a>(i: &'a str, declarations: &Declarations) -> IResult<&'a str, crate::Formula> +fn function_or_predicate<'i>(i: &'i str, declarations: &Declarations) + -> IResult<&'i str, (&'i str, Option>>)> { - alt - (( - function_n_ary, - function_0_ary - ))(i) -} - -fn function_0_ary<'a>(i: &'a str, declarations: &Declarations) -> IResult<&'a str, crate::Term> -{ - map + pair ( - delimited(multispace0, function_identifier, multispace0), - |name| crate::Formula::function( - crate::FunctionDeclaration - { - name: name, - arity: 0, - }, - vec![]) - )(i) -} - -fn function_n_ary<'a>(i: &'a str, declarations: &Declarations) -> IResult<&'a str, crate::Term> -{ - map - ( - pair + function_or_predicate_name, + opt ( - delimited(multispace0, function_identifier, multispace0), delimited ( - multispace0, delimited ( + multispace0, tag("("), - separated_list(tag(","), term), - tag(")") + multispace0, + ), + separated_list + ( + delimited + ( + multispace0, + tag(","), + multispace0, + ), + // TODO: fix + map + ( + integer, + Box::new, + ), + ), + preceded + ( + multispace0, + tag(")"), ), - multispace0 ) ), - |(name, arguments)| crate::Formula::function( - crate::PredicateDeclaration - { - name: name, - arity: arguments.len(), - }, - arguments) )(i) } -*/ +pub fn function<'i>(i: &'i str, declarations: &Declarations) -> IResult<&'i str, crate::Function> +{ + map + ( + |i| function_or_predicate(i, declarations), + |(name, arguments)| + { + let arguments = match arguments + { + Some(arguments) => arguments, + None => vec![], + }; + + let mut function_declarations = declarations.function_declarations.borrow_mut(); + + let declaration = match function_declarations.iter() + .find(|x| x.name == name && x.arity == arguments.len()) + { + Some(declaration) => std::rc::Rc::clone(&declaration), + None => + { + let declaration = crate::FunctionDeclaration + { + name: name.to_string(), + arity: arguments.len(), + }; + let declaration = std::rc::Rc::new(declaration); + + function_declarations.insert(std::rc::Rc::clone(&declaration)); + + declaration + }, + }; + + crate::Function::new(declaration, arguments) + }, + )(i) +} + +pub fn predicate<'i>(i: &'i str, declarations: &Declarations) -> IResult<&'i str, crate::Predicate> +{ + map + ( + |i| function_or_predicate(i, declarations), + |(name, arguments)| + { + let arguments = match arguments + { + Some(arguments) => arguments, + None => vec![], + }; + + let mut predicate_declarations = declarations.predicate_declarations.borrow_mut(); + + let declaration = match predicate_declarations.iter() + .find(|x| x.name == name && x.arity == arguments.len()) + { + Some(declaration) => std::rc::Rc::clone(&declaration), + None => + { + let declaration = crate::PredicateDeclaration + { + name: name.to_string(), + arity: arguments.len(), + }; + let declaration = std::rc::Rc::new(declaration); + + predicate_declarations.insert(std::rc::Rc::clone(&declaration)); + + declaration + }, + }; + + crate::Predicate::new(declaration, arguments) + }, + )(i) +} + +pub fn variable_declaration(i: &str) -> IResult<&str, crate::VariableDeclaration> +{ + map + ( + variable_name, + |name| crate::VariableDeclaration::new(name.to_string()) + )(i) +} + +pub fn variable<'i>(i: &'i str, declarations: &Declarations) -> IResult<&'i str, crate::Variable> +{ + map + ( + variable_name, + |name| + { + let mut variable_declaration_stack = + declarations.variable_declaration_stack.borrow_mut(); + + let declaration = variable_declaration_stack.find_or_create(name); + + crate::Variable::new(declaration) + }, + )(i) +} #[cfg(test)] mod tests @@ -304,4 +394,172 @@ mod tests assert!(string("-").is_err()); assert!(string(" ").is_err()); } + + #[test] + fn parse_function() + { + assert_eq!(function("s", &Declarations::new()) + .map(|(i, x)| (i, x.declaration.name.clone())), + Ok(("", "s".to_string()))); + assert_eq!(function("s", &Declarations::new()) + .map(|(i, x)| (i, x.declaration.arity)), + Ok(("", 0))); + assert_eq!(function("s ( )", &Declarations::new()) + .map(|(i, x)| (i, x.declaration.name.clone())), + Ok(("", "s".to_string()))); + assert_eq!(function("s ( )", &Declarations::new()) + .map(|(i, x)| (i, x.declaration.arity)), + Ok(("", 0))); + assert_eq!(function("s ( 1 , 2 , 3 )", &Declarations::new()) + .map(|(i, x)| (i, x.declaration.name.clone())), + Ok(("", "s".to_string()))); + assert_eq!(function("s ( 1 , 2 , 3 )", &Declarations::new()) + .map(|(i, x)| (i, x.declaration.arity)), + Ok(("", 3))); + assert_eq!(function("s ( 1 , 2 , 3 )", &Declarations::new()) + .map(|(i, mut x)| (i, x.arguments.remove(0))), + Ok(("", Box::new(Term::integer(1))))); + assert_eq!(function("s ( 1 , 2 , 3 )", &Declarations::new()) + .map(|(i, mut x)| (i, x.arguments.remove(2))), + Ok(("", Box::new(Term::integer(3))))); + assert_eq!(function("s ( ), rest", &Declarations::new()) + .map(|(i, x)| (i, x.declaration.name.clone())), + Ok((", rest", "s".to_string()))); + assert_eq!(function("s ( ), rest", &Declarations::new()) + .map(|(i, x)| (i, x.declaration.arity)), + Ok((", rest", 0))); + assert_eq!(function("s ( 1 , 2 , 3 ), rest", &Declarations::new()) + .map(|(i, x)| (i, x.declaration.name.clone())), + Ok((", rest", "s".to_string()))); + assert_eq!(function("s ( 1 , 2 , 3 ), rest", &Declarations::new()) + .map(|(i, x)| (i, x.declaration.arity)), + Ok((", rest", 3))); + } + + #[test] + fn parse_variable_declaration() + { + assert_eq!(variable_declaration("X Rest") + .map(|(i, x)| (i, x.name.clone())), Ok((" Rest", "X".to_string()))); + assert_eq!(variable_declaration("X, Rest") + .map(|(i, x)| (i, x.name.clone())), Ok((", Rest", "X".to_string()))); + // Variable declarations parsed at different locations should not be considered equal + assert_ne!(variable_declaration("X"), variable_declaration("X")); + assert_eq!(variable_declaration("Variable_123 Rest") + .map(|(i, x)| (i, x.name.clone())), Ok((" Rest", "Variable_123".to_string()))); + assert!(variable_declaration("0 Rest").is_err()); + assert!(variable_declaration("123_Asd Rest").is_err()); + assert!(variable_declaration("x Rest").is_err()); + assert!(variable_declaration("variable_123 Rest").is_err()); + assert!(variable_declaration("_ Rest").is_err()); + assert!(variable_declaration("_variable_123 Rest").is_err()); + assert!(variable_declaration(" ").is_err()); + } + + #[test] + fn parse_variable() + { + assert_eq!(variable("X Rest", &Declarations::new()) + .map(|(i, x)| (i, x.declaration.name.clone())), Ok((" Rest", "X".to_string()))); + assert_eq!(variable("X, Rest", &Declarations::new()) + .map(|(i, x)| (i, x.declaration.name.clone())), Ok((", Rest", "X".to_string()))); + assert_eq!(variable("Variable_123 Rest", &Declarations::new()) + .map(|(i, x)| (i, x.declaration.name.clone())), + Ok((" Rest", "Variable_123".to_string()))); + assert!(variable("0 Rest", &Declarations::new()).is_err()); + assert!(variable("123_Asd Rest", &Declarations::new()).is_err()); + assert!(variable("x Rest", &Declarations::new()).is_err()); + assert!(variable("variable_123 Rest", &Declarations::new()).is_err()); + assert!(variable("_ Rest", &Declarations::new()).is_err()); + assert!(variable("_variable_123 Rest", &Declarations::new()).is_err()); + assert!(variable(" ", &Declarations::new()).is_err()); + + let new_variable_declarations = |names: &[&str]| std::rc::Rc::new(names.iter() + .map(|name| std::rc::Rc::new(crate::VariableDeclaration::new(name.to_string()))) + .collect()); + + let layer_1 = new_variable_declarations(&["A", "B", "X"]); + let layer_2 = new_variable_declarations(&["C", "D", "X"]); + let layer_3 = new_variable_declarations(&["E", "F", "Y"]); + let layer_4 = new_variable_declarations(&["G", "H", "X"]); + + let variable_declaration_stack = crate::VariableDeclarationStack::new(); + + let mut declarations = Declarations::new(); + declarations.variable_declaration_stack = + std::cell::RefCell::new(variable_declaration_stack); + + let (_, x1) = variable("X", &declarations).unwrap(); + assert_eq!(declarations.variable_declaration_stack.borrow() + .free_variable_declarations.len(), 1); + let (_, x2) = variable("X", &declarations).unwrap(); + assert_eq!(declarations.variable_declaration_stack.borrow() + .free_variable_declarations.len(), 1); + assert_eq!(x1.declaration, x2.declaration); + let (_, y1) = variable("Y", &declarations).unwrap(); + assert_eq!(declarations.variable_declaration_stack.borrow() + .free_variable_declarations.len(), 2); + assert_ne!(x1.declaration, y1.declaration); + assert_ne!(x2.declaration, y1.declaration); + + declarations.variable_declaration_stack.borrow_mut().push(layer_1); + + let (_, x3) = variable("X", &declarations).unwrap(); + assert_eq!(declarations.variable_declaration_stack.borrow() + .free_variable_declarations.len(), 2); + assert_ne!(x1.declaration, x3.declaration); + let (_, x4) = variable("X", &declarations).unwrap(); + assert_eq!(declarations.variable_declaration_stack.borrow() + .free_variable_declarations.len(), 2); + assert_eq!(x3.declaration, x4.declaration); + let (_, a1) = variable("A", &declarations).unwrap(); + assert_eq!(declarations.variable_declaration_stack.borrow() + .free_variable_declarations.len(), 2); + assert_ne!(x3.declaration, a1.declaration); + let (_, y2) = variable("Y", &declarations).unwrap(); + assert_eq!(declarations.variable_declaration_stack.borrow() + .free_variable_declarations.len(), 2); + assert_eq!(y1.declaration, y2.declaration); + + declarations.variable_declaration_stack.borrow_mut().push(layer_2); + + let (_, x5) = variable("X", &declarations).unwrap(); + assert_eq!(declarations.variable_declaration_stack.borrow() + .free_variable_declarations.len(), 2); + assert_ne!(x1.declaration, x5.declaration); + assert_ne!(x3.declaration, x5.declaration); + let (_, x6) = variable("X", &declarations).unwrap(); + assert_eq!(declarations.variable_declaration_stack.borrow() + .free_variable_declarations.len(), 2); + assert_eq!(x5.declaration, x6.declaration); + let (_, a2) = variable("A", &declarations).unwrap(); + assert_eq!(declarations.variable_declaration_stack.borrow() + .free_variable_declarations.len(), 2); + assert_eq!(a1.declaration, a2.declaration); + + declarations.variable_declaration_stack.borrow_mut().push(layer_3); + + let (_, x7) = variable("X", &declarations).unwrap(); + assert_eq!(declarations.variable_declaration_stack.borrow() + .free_variable_declarations.len(), 2); + assert_eq!(x5.declaration, x7.declaration); + let (_, y3) = variable("Y", &declarations).unwrap(); + assert_eq!(declarations.variable_declaration_stack.borrow() + .free_variable_declarations.len(), 2); + assert_ne!(y2.declaration, y3.declaration); + + declarations.variable_declaration_stack.borrow_mut().push(layer_4); + + let (_, x8) = variable("X", &declarations).unwrap(); + assert_eq!(declarations.variable_declaration_stack.borrow() + .free_variable_declarations.len(), 2); + assert_ne!(x7.declaration, x8.declaration); + let (_, y4) = variable("Y", &declarations).unwrap(); + assert_eq!(declarations.variable_declaration_stack.borrow() + .free_variable_declarations.len(), 2); + assert_eq!(y3.declaration, y4.declaration); + let _ = variable("I", &declarations).unwrap(); + assert_eq!(declarations.variable_declaration_stack.borrow() + .free_variable_declarations.len(), 3); + } } diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..473836e --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,72 @@ +pub struct VariableDeclarationStack +{ + pub free_variable_declarations: crate::VariableDeclarations, + bound_variable_declaration_stack: Vec>, +} + +impl VariableDeclarationStack +{ + pub fn new() -> Self + { + Self + { + free_variable_declarations: crate::VariableDeclarations::new(), + bound_variable_declaration_stack: vec![], + } + } + + pub fn find(&self, variable_name: &str) -> Option> + { + for variable_declarations in self.bound_variable_declaration_stack.iter().rev() + { + if let Some(variable_declaration) = variable_declarations.iter() + .find(|x| x.name == variable_name) + { + return Some(std::rc::Rc::clone(&variable_declaration)); + } + } + + if let Some(variable_declaration) = self.free_variable_declarations.iter() + .find(|x| x.name == variable_name) + { + return Some(std::rc::Rc::clone(&variable_declaration)); + } + + None + } + + pub fn find_or_create(&mut self, variable_name: &str) -> std::rc::Rc + { + if let Some(variable_declaration) = self.find(variable_name) + { + return variable_declaration; + } + + let variable_declaration = crate::VariableDeclaration + { + name: variable_name.to_owned(), + }; + let variable_declaration = std::rc::Rc::new(variable_declaration); + + self.free_variable_declarations.push(std::rc::Rc::clone(&variable_declaration)); + + variable_declaration + } + + pub fn is_empty(&self) -> bool + { + self.free_variable_declarations.is_empty() + && self.bound_variable_declaration_stack.is_empty() + } + + pub fn push(&mut self, bound_variable_declarations: std::rc::Rc) + { + self.bound_variable_declaration_stack.push(bound_variable_declarations); + } + + pub fn pop(&mut self) -> Result<(), crate::Error> + { + self.bound_variable_declaration_stack.pop().map(|_| ()) + .ok_or(crate::Error::new_logic("variable stack not in expected state")) + } +}