Start rewriting parser
This commit is contained in:
parent
b516396977
commit
ff17c60cd1
@ -11,10 +11,3 @@ keywords = ["logic"]
|
||||
categories = ["data-structures", "science"]
|
||||
license = "MIT"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
nom = {version = ">=6.0.0-alpha1, <6.1", optional = true}
|
||||
|
||||
[features]
|
||||
default = ["parse"]
|
||||
parse = ["nom"]
|
||||
|
@ -1,6 +1,5 @@
|
||||
mod ast;
|
||||
pub mod format;
|
||||
#[cfg(feature = "parse")]
|
||||
pub mod parse;
|
||||
mod utils;
|
||||
|
||||
|
10
src/parse.rs
10
src/parse.rs
@ -1,4 +1,4 @@
|
||||
mod formulas;
|
||||
/*mod formulas;
|
||||
mod helpers;
|
||||
mod literals;
|
||||
mod names;
|
||||
@ -9,4 +9,10 @@ pub(crate) use literals::{boolean, integer, special_integer, string};
|
||||
pub use names::function_or_predicate_name;
|
||||
pub(crate) use names::variable_name;
|
||||
pub use terms::term;
|
||||
pub use formulas::formula;
|
||||
pub use formulas::formula;*/
|
||||
|
||||
pub mod error;
|
||||
pub mod formulas;
|
||||
pub mod tokens;
|
||||
|
||||
pub use error::Error;
|
||||
|
129
src/parse/error.rs
Normal file
129
src/parse/error.rs
Normal file
@ -0,0 +1,129 @@
|
||||
pub type Source = Box<dyn std::error::Error>;
|
||||
|
||||
pub struct Location
|
||||
{
|
||||
start: usize,
|
||||
end: Option<usize>,
|
||||
}
|
||||
|
||||
impl Location
|
||||
{
|
||||
pub fn new(start: usize, end: Option<usize>) -> Self
|
||||
{
|
||||
Self
|
||||
{
|
||||
start,
|
||||
end,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Kind
|
||||
{
|
||||
UnmatchedParenthesis,
|
||||
CharacterNotAllowed(char),
|
||||
ParseNumber(String),
|
||||
MixedImplicationDirections(Location),
|
||||
}
|
||||
|
||||
pub struct Error
|
||||
{
|
||||
pub kind: Kind,
|
||||
pub location: Location,
|
||||
pub source: Option<Source>,
|
||||
}
|
||||
|
||||
impl Error
|
||||
{
|
||||
pub(crate) fn new(kind: Kind, location: Location) -> Self
|
||||
{
|
||||
Self
|
||||
{
|
||||
kind,
|
||||
location,
|
||||
source: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn with<S: Into<Source>>(mut self, source: S) -> Self
|
||||
{
|
||||
self.source = Some(source.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn new_unmatched_parenthesis(location: Location) -> Self
|
||||
{
|
||||
Self::new(Kind::UnmatchedParenthesis, location)
|
||||
}
|
||||
|
||||
pub(crate) fn new_character_not_allowed(character: char, location: Location) -> Self
|
||||
{
|
||||
Self::new(Kind::CharacterNotAllowed(character), location)
|
||||
}
|
||||
|
||||
pub(crate) fn new_parse_number<I: Into<String>, S: Into<Source>>(input: I, location: Location,
|
||||
source: S)
|
||||
-> Self
|
||||
{
|
||||
Self::new(Kind::ParseNumber(input.into()), location).with(source)
|
||||
}
|
||||
|
||||
pub(crate) fn new_mixed_implication_directions(location_1: Location, location_2: Location)
|
||||
-> Self
|
||||
{
|
||||
Self::new(Kind::MixedImplicationDirections(location_2), location_1)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Error
|
||||
{
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||
{
|
||||
if let Some(end) = self.location.end
|
||||
{
|
||||
write!(formatter, "parsing error at {}:{}: ", self.location.start, end)?;
|
||||
}
|
||||
else
|
||||
{
|
||||
write!(formatter, "parsing error at {}: ", self.location.start)?;
|
||||
}
|
||||
|
||||
match &self.kind
|
||||
{
|
||||
Kind::UnmatchedParenthesis => write!(formatter, "unmatched parenthesis")?,
|
||||
Kind::CharacterNotAllowed(character) =>
|
||||
write!(formatter, "character not allowed: ‘{}’", character)?,
|
||||
Kind::ParseNumber(input) => write!(formatter, "could not “{}” as number", input)?,
|
||||
// TODO: print second location properly
|
||||
Kind::MixedImplicationDirections(_location_2) =>
|
||||
write!(formatter, "-> and <- implications may not be mixed within the same scope")?,
|
||||
}
|
||||
|
||||
if let Some(source) = &self.source
|
||||
{
|
||||
write!(formatter, "\nerror source: {}", source)?;
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,87 +0,0 @@
|
||||
use nom::
|
||||
{
|
||||
IResult,
|
||||
branch::alt,
|
||||
bytes::complete::take_while_m_n,
|
||||
combinator::{map, peek, rest_len, verify},
|
||||
};
|
||||
|
||||
fn is_character_word_boundary(c: char) -> bool
|
||||
{
|
||||
if c.is_whitespace()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
match c
|
||||
{
|
||||
'('
|
||||
| ')'
|
||||
| '>'
|
||||
| '<'
|
||||
| '='
|
||||
| ','
|
||||
| '+'
|
||||
| '-'
|
||||
| '*'
|
||||
| '/'
|
||||
| '%'
|
||||
| '|'
|
||||
| '#'
|
||||
| '.'
|
||||
=> true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn word_boundary(i: &str) -> IResult<&str, ()>
|
||||
{
|
||||
peek
|
||||
(
|
||||
alt
|
||||
((
|
||||
// Accept word boundary characters
|
||||
map
|
||||
(
|
||||
take_while_m_n(1, 1, is_character_word_boundary),
|
||||
|_| (),
|
||||
),
|
||||
// Accept end of file
|
||||
map
|
||||
(
|
||||
verify
|
||||
(
|
||||
rest_len,
|
||||
|rest_length| *rest_length == 0usize,
|
||||
),
|
||||
|_| (),
|
||||
),
|
||||
))
|
||||
)(i)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests
|
||||
{
|
||||
use crate::parse::*;
|
||||
|
||||
#[test]
|
||||
fn detect_word_boundaries()
|
||||
{
|
||||
assert_eq!(word_boundary(" rest"), Ok((" rest", ())));
|
||||
assert_eq!(word_boundary("(rest"), Ok(("(rest", ())));
|
||||
assert_eq!(word_boundary(")rest"), Ok((")rest", ())));
|
||||
assert_eq!(word_boundary(",rest"), Ok((",rest", ())));
|
||||
assert_eq!(word_boundary("+rest"), Ok(("+rest", ())));
|
||||
assert_eq!(word_boundary("-rest"), Ok(("-rest", ())));
|
||||
assert_eq!(word_boundary("*rest"), Ok(("*rest", ())));
|
||||
assert_eq!(word_boundary("/rest"), Ok(("/rest", ())));
|
||||
assert_eq!(word_boundary("%rest"), Ok(("%rest", ())));
|
||||
assert_eq!(word_boundary("|rest"), Ok(("|rest", ())));
|
||||
assert_eq!(word_boundary("<rest"), Ok(("<rest", ())));
|
||||
assert_eq!(word_boundary(">rest"), Ok((">rest", ())));
|
||||
assert_eq!(word_boundary("=rest"), Ok(("=rest", ())));
|
||||
assert!(word_boundary("0").is_err());
|
||||
assert!(word_boundary("rest").is_err());
|
||||
}
|
||||
}
|
@ -1,249 +0,0 @@
|
||||
use nom::
|
||||
{
|
||||
IResult,
|
||||
branch::alt,
|
||||
bytes::complete::{escaped_transform, tag},
|
||||
character::complete::{digit1, none_of},
|
||||
combinator::{map, map_res, opt, recognize},
|
||||
sequence::{delimited, pair, terminated},
|
||||
};
|
||||
|
||||
use super::word_boundary;
|
||||
|
||||
fn true_(i: &str) -> IResult<&str, bool>
|
||||
{
|
||||
map
|
||||
(
|
||||
terminated
|
||||
(
|
||||
tag("true"),
|
||||
word_boundary,
|
||||
),
|
||||
|_| true,
|
||||
)(i)
|
||||
}
|
||||
|
||||
fn false_(i: &str) -> IResult<&str, bool>
|
||||
{
|
||||
map
|
||||
(
|
||||
terminated
|
||||
(
|
||||
tag("false"),
|
||||
word_boundary,
|
||||
),
|
||||
|_| false,
|
||||
)(i)
|
||||
}
|
||||
|
||||
pub fn boolean(i: &str) -> IResult<&str, bool>
|
||||
{
|
||||
alt
|
||||
((
|
||||
true_,
|
||||
false_,
|
||||
))(i)
|
||||
}
|
||||
|
||||
pub fn integer(i: &str) -> IResult<&str, i32>
|
||||
{
|
||||
map_res
|
||||
(
|
||||
recognize
|
||||
(
|
||||
terminated
|
||||
(
|
||||
pair
|
||||
(
|
||||
opt
|
||||
(
|
||||
alt
|
||||
((
|
||||
tag("-"),
|
||||
tag("+"),
|
||||
))
|
||||
),
|
||||
digit1,
|
||||
),
|
||||
word_boundary,
|
||||
)
|
||||
),
|
||||
std::str::FromStr::from_str,
|
||||
)(i)
|
||||
}
|
||||
|
||||
fn infimum(i: &str) -> IResult<&str, crate::SpecialInteger>
|
||||
{
|
||||
map
|
||||
(
|
||||
terminated
|
||||
(
|
||||
tag("#inf"),
|
||||
word_boundary,
|
||||
),
|
||||
|_| crate::SpecialInteger::Infimum,
|
||||
)(i)
|
||||
}
|
||||
|
||||
fn supremum(i: &str) -> IResult<&str, crate::SpecialInteger>
|
||||
{
|
||||
map
|
||||
(
|
||||
terminated
|
||||
(
|
||||
tag("#sup"),
|
||||
word_boundary,
|
||||
),
|
||||
|_| crate::SpecialInteger::Supremum,
|
||||
)(i)
|
||||
}
|
||||
|
||||
pub fn special_integer(i: &str) -> IResult<&str, crate::SpecialInteger>
|
||||
{
|
||||
alt
|
||||
((
|
||||
infimum,
|
||||
supremum,
|
||||
))(i)
|
||||
}
|
||||
|
||||
pub fn string(i: &str) -> IResult<&str, String>
|
||||
{
|
||||
map
|
||||
(
|
||||
terminated
|
||||
(
|
||||
delimited
|
||||
(
|
||||
tag("\""),
|
||||
escaped_transform
|
||||
(
|
||||
none_of("\"\\"),
|
||||
'\\',
|
||||
alt
|
||||
((
|
||||
tag("\""),
|
||||
tag("\\"),
|
||||
map
|
||||
(
|
||||
tag("n"),
|
||||
|_| "\n",
|
||||
),
|
||||
map
|
||||
(
|
||||
tag("t"),
|
||||
|_| "\t",
|
||||
),
|
||||
)),
|
||||
),
|
||||
tag("\""),
|
||||
),
|
||||
word_boundary,
|
||||
),
|
||||
String::from,
|
||||
)(i)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests
|
||||
{
|
||||
use crate::SpecialInteger;
|
||||
use crate::parse::*;
|
||||
|
||||
#[test]
|
||||
fn parse_boolean()
|
||||
{
|
||||
assert_eq!(boolean("true"), Ok(("", true)));
|
||||
assert_eq!(boolean("false"), Ok(("", false)));
|
||||
assert_eq!(boolean("true false"), Ok((" false", true)));
|
||||
assert_eq!(boolean("false true"), Ok((" true", false)));
|
||||
assert_eq!(boolean("true,"), Ok((",", true)));
|
||||
assert_eq!(boolean("false,"), Ok((",", false)));
|
||||
assert!(boolean("truefalse").is_err());
|
||||
assert!(boolean("falsetrue").is_err());
|
||||
assert!(boolean("truea").is_err());
|
||||
assert!(boolean("falsea").is_err());
|
||||
assert!(boolean("a").is_err());
|
||||
assert!(boolean("-").is_err());
|
||||
assert!(boolean(" ").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_integer()
|
||||
{
|
||||
assert_eq!(integer("0"), Ok(("", 0)));
|
||||
assert_eq!(integer("10000"), Ok(("", 10000)));
|
||||
assert_eq!(integer("+10000"), Ok(("", 10000)));
|
||||
assert_eq!(integer("-10000"), Ok(("", -10000)));
|
||||
assert_eq!(integer("0 42"), Ok((" 42", 0)));
|
||||
assert_eq!(integer("10000 42"), Ok((" 42", 10000)));
|
||||
assert_eq!(integer("+10000 42"), Ok((" 42", 10000)));
|
||||
assert_eq!(integer("-10000 42"), Ok((" 42", -10000)));
|
||||
assert_eq!(integer("10000,"), Ok((",", 10000)));
|
||||
assert_eq!(integer("+10000,"), Ok((",", 10000)));
|
||||
assert_eq!(integer("-10000,"), Ok((",", -10000)));
|
||||
assert!(integer("10000a").is_err());
|
||||
assert!(integer("+10000a").is_err());
|
||||
assert!(integer("-10000a").is_err());
|
||||
assert_eq!(integer("1.5"), Ok((".5", 1)));
|
||||
assert!(integer("a").is_err());
|
||||
assert!(integer("-").is_err());
|
||||
assert!(integer(" ").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_special_integer()
|
||||
{
|
||||
assert_eq!(special_integer("#inf"), Ok(("", SpecialInteger::Infimum)));
|
||||
assert_eq!(special_integer("#sup"), Ok(("", SpecialInteger::Supremum)));
|
||||
assert_eq!(special_integer("#inf #sup"), Ok((" #sup", SpecialInteger::Infimum)));
|
||||
assert_eq!(special_integer("#sup #inf"), Ok((" #inf", SpecialInteger::Supremum)));
|
||||
assert_eq!(special_integer("#inf,"), Ok((",", SpecialInteger::Infimum)));
|
||||
assert_eq!(special_integer("#sup,"), Ok((",", SpecialInteger::Supremum)));
|
||||
assert!(special_integer("#inf0").is_err());
|
||||
assert!(special_integer("#sup0").is_err());
|
||||
assert!(special_integer("#infimum").is_err());
|
||||
assert!(special_integer("#supremum").is_err());
|
||||
assert!(special_integer("inf").is_err());
|
||||
assert!(special_integer("sup").is_err());
|
||||
assert!(special_integer("0").is_err());
|
||||
assert!(special_integer("10000").is_err());
|
||||
assert!(special_integer("-10000").is_err());
|
||||
assert!(special_integer("-").is_err());
|
||||
assert!(special_integer("+").is_err());
|
||||
assert!(special_integer("a").is_err());
|
||||
assert!(special_integer(" ").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_string()
|
||||
{
|
||||
assert_eq!(string("\"test 123\""), Ok(("", "test 123".to_string())));
|
||||
assert_eq!(string("\"123 test\""), Ok(("", "123 test".to_string())));
|
||||
assert_eq!(string("\" test 123 \""), Ok(("", " test 123 ".to_string())));
|
||||
assert_eq!(string("\"test 123\" \"rest"), Ok((" \"rest", "test 123".to_string())));
|
||||
assert_eq!(string("\"test 123\", \"rest"), Ok((", \"rest", "test 123".to_string())));
|
||||
assert_eq!(string("\"test\n123\""), Ok(("", "test\n123".to_string())));
|
||||
assert_eq!(string("\"test\\\"123\""), Ok(("", "test\"123".to_string())));
|
||||
assert_eq!(string("\"test\\\"123\\\"\""), Ok(("", "test\"123\"".to_string())));
|
||||
assert_eq!(string("\"\\\"test 123\\\"\""), Ok(("", "\"test 123\"".to_string())));
|
||||
assert_eq!(string("\"test\\\\123\""), Ok(("", "test\\123".to_string())));
|
||||
assert_eq!(string("\"test\\\\123\\\\\""), Ok(("", "test\\123\\".to_string())));
|
||||
assert_eq!(string("\"\\\\test 123\\\\\""), Ok(("", "\\test 123\\".to_string())));
|
||||
assert_eq!(string("\"test\\n123\""), Ok(("", "test\n123".to_string())));
|
||||
assert_eq!(string("\"test\\n123\\n\""), Ok(("", "test\n123\n".to_string())));
|
||||
assert_eq!(string("\"\\ntest 123\\n\""), Ok(("", "\ntest 123\n".to_string())));
|
||||
assert_eq!(string("\"test\\t123\""), Ok(("", "test\t123".to_string())));
|
||||
assert_eq!(string("\"test\\t123\\t\""), Ok(("", "test\t123\t".to_string())));
|
||||
assert_eq!(string("\"\\ttest 123\\t\""), Ok(("", "\ttest 123\t".to_string())));
|
||||
assert_eq!(string("\"test 🙂 123\""), Ok(("", "test 🙂 123".to_string())));
|
||||
assert_eq!(string("\"🙂test 123\""), Ok(("", "🙂test 123".to_string())));
|
||||
assert_eq!(string("\"test 123🙂\""), Ok(("", "test 123🙂".to_string())));
|
||||
assert!(string("\"test 123\"a").is_err());
|
||||
assert!(string("\"test\\i123\"").is_err());
|
||||
assert!(string("\"test").is_err());
|
||||
assert!(string("test").is_err());
|
||||
assert!(string("-").is_err());
|
||||
assert!(string(" ").is_err());
|
||||
}
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
use nom::
|
||||
{
|
||||
IResult,
|
||||
bytes::complete::{take_while, take_while_m_n},
|
||||
combinator::recognize,
|
||||
sequence::{pair, terminated},
|
||||
};
|
||||
|
||||
use super::word_boundary;
|
||||
|
||||
fn is_function_name_character_first(c: char) -> bool
|
||||
{
|
||||
c.is_alphabetic() && c.is_lowercase()
|
||||
}
|
||||
|
||||
fn is_function_name_character_body(c: char) -> bool
|
||||
{
|
||||
c.is_alphanumeric() || c == '_'
|
||||
}
|
||||
|
||||
fn is_variable_name_character_first(c: char) -> bool
|
||||
{
|
||||
c.is_alphabetic() && c.is_uppercase()
|
||||
}
|
||||
|
||||
fn is_variable_name_character_body(c: char) -> bool
|
||||
{
|
||||
c.is_alphanumeric() || c == '_'
|
||||
}
|
||||
|
||||
pub fn function_or_predicate_name(i: &str) -> IResult<&str, &str>
|
||||
{
|
||||
let (i, name) =
|
||||
recognize
|
||||
(
|
||||
terminated
|
||||
(
|
||||
pair
|
||||
(
|
||||
take_while_m_n(1, 1, is_function_name_character_first),
|
||||
take_while(is_function_name_character_body),
|
||||
),
|
||||
word_boundary,
|
||||
)
|
||||
)(i)?;
|
||||
|
||||
match name
|
||||
{
|
||||
"and"
|
||||
| "exists"
|
||||
| "false"
|
||||
| "forall"
|
||||
| "not"
|
||||
| "or"
|
||||
| "true"
|
||||
=> Err(nom::Err::Error((i, nom::error::ErrorKind::Verify))),
|
||||
name => Ok((i, name)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn variable_name(i: &str) -> IResult<&str, &str>
|
||||
{
|
||||
recognize
|
||||
(
|
||||
terminated
|
||||
(
|
||||
pair
|
||||
(
|
||||
take_while_m_n(1, 1, is_variable_name_character_first),
|
||||
take_while(is_variable_name_character_body),
|
||||
),
|
||||
word_boundary,
|
||||
)
|
||||
)(i)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests
|
||||
{
|
||||
use crate::parse::*;
|
||||
|
||||
#[test]
|
||||
fn parse_function_or_predicate_name()
|
||||
{
|
||||
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("(p").is_err());
|
||||
assert!(function_or_predicate_name(")p").is_err());
|
||||
assert!(function_or_predicate_name(">p").is_err());
|
||||
assert!(function_or_predicate_name("<p").is_err());
|
||||
assert!(function_or_predicate_name("=p").is_err());
|
||||
assert!(function_or_predicate_name(",p").is_err());
|
||||
assert!(function_or_predicate_name("+p").is_err());
|
||||
assert!(function_or_predicate_name("-p").is_err());
|
||||
assert!(function_or_predicate_name("*p").is_err());
|
||||
assert!(function_or_predicate_name("/p").is_err());
|
||||
assert!(function_or_predicate_name("%p").is_err());
|
||||
assert!(function_or_predicate_name("|p").is_err());
|
||||
assert!(function_or_predicate_name("#inf").is_err());
|
||||
assert!(function_or_predicate_name("#sup").is_err());
|
||||
assert!(function_or_predicate_name("#p").is_err());
|
||||
assert!(function_or_predicate_name(" ").is_err());
|
||||
// Keywords aren’t valid names
|
||||
assert!(function_or_predicate_name("and rest").is_err());
|
||||
assert!(function_or_predicate_name("exists rest").is_err());
|
||||
assert!(function_or_predicate_name("false rest").is_err());
|
||||
assert!(function_or_predicate_name("forall rest").is_err());
|
||||
assert!(function_or_predicate_name("or rest").is_err());
|
||||
assert!(function_or_predicate_name("not rest").is_err());
|
||||
assert!(function_or_predicate_name("true rest").is_err());
|
||||
// Names that start with keywords are fine though
|
||||
assert!(function_or_predicate_name("anda rest").is_ok());
|
||||
assert!(function_or_predicate_name("existsa rest").is_ok());
|
||||
assert!(function_or_predicate_name("falsea rest").is_ok());
|
||||
assert!(function_or_predicate_name("foralla rest").is_ok());
|
||||
assert!(function_or_predicate_name("ora rest").is_ok());
|
||||
assert!(function_or_predicate_name("nota rest").is_ok());
|
||||
assert!(function_or_predicate_name("truea rest").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_variable_name()
|
||||
{
|
||||
assert_eq!(variable_name("X Rest"), Ok((" Rest", "X")));
|
||||
assert_eq!(variable_name("X, Rest"), Ok((", Rest", "X")));
|
||||
assert_eq!(variable_name("Variable_123 Rest"), Ok((" Rest", "Variable_123")));
|
||||
assert!(variable_name("0 Rest").is_err());
|
||||
assert!(variable_name("123_Asd Rest").is_err());
|
||||
assert!(variable_name("x Rest").is_err());
|
||||
assert!(variable_name("variable_123 Rest").is_err());
|
||||
assert!(variable_name("_ Rest").is_err());
|
||||
assert!(variable_name("_variable_123 Rest").is_err());
|
||||
assert!(variable_name("(X").is_err());
|
||||
assert!(variable_name(")X").is_err());
|
||||
assert!(variable_name(">X").is_err());
|
||||
assert!(variable_name("<X").is_err());
|
||||
assert!(variable_name("=X").is_err());
|
||||
assert!(variable_name(",X").is_err());
|
||||
assert!(variable_name("+X").is_err());
|
||||
assert!(variable_name("-X").is_err());
|
||||
assert!(variable_name("*X").is_err());
|
||||
assert!(variable_name("/X").is_err());
|
||||
assert!(variable_name("%X").is_err());
|
||||
assert!(variable_name("|X").is_err());
|
||||
assert!(variable_name("#inf").is_err());
|
||||
assert!(variable_name("#sup").is_err());
|
||||
assert!(variable_name("#X").is_err());
|
||||
assert!(variable_name(" ").is_err());
|
||||
}
|
||||
}
|
@ -1,872 +0,0 @@
|
||||
use nom::
|
||||
{
|
||||
IResult,
|
||||
branch::alt,
|
||||
bytes::complete::tag,
|
||||
character::complete::multispace0,
|
||||
combinator::{map, opt},
|
||||
multi::{many1, separated_list0},
|
||||
sequence::{delimited, pair, preceded, terminated},
|
||||
};
|
||||
|
||||
use super::{boolean, function_or_predicate_name, integer, special_integer, string, variable_name};
|
||||
|
||||
fn negative<'i, 'v, D>(i: &'i str, d: &D, v: &'v crate::VariableDeclarationStackLayer)
|
||||
-> IResult<&'i str, crate::Term>
|
||||
where
|
||||
D: crate::FindOrCreateFunctionDeclaration + crate::FindOrCreatePredicateDeclaration
|
||||
{
|
||||
map
|
||||
(
|
||||
preceded
|
||||
(
|
||||
terminated
|
||||
(
|
||||
tag("-"),
|
||||
multispace0,
|
||||
),
|
||||
|i| term_precedence_1(i, d, v),
|
||||
),
|
||||
|x| match x
|
||||
{
|
||||
crate::Term::Integer(value) => crate::Term::integer(-value),
|
||||
crate::Term::UnaryOperation(
|
||||
crate::UnaryOperation{operator: crate::UnaryOperator::Negative, argument})
|
||||
=> *argument,
|
||||
_ => crate::Term::negative(Box::new(x)),
|
||||
}
|
||||
)(i)
|
||||
}
|
||||
|
||||
fn absolute_value<'i, 'v, D>(i: &'i str, d: &D, v: &'v crate::VariableDeclarationStackLayer)
|
||||
-> IResult<&'i str, crate::Term>
|
||||
where
|
||||
D: crate::FindOrCreateFunctionDeclaration + crate::FindOrCreatePredicateDeclaration
|
||||
{
|
||||
map
|
||||
(
|
||||
delimited
|
||||
(
|
||||
terminated
|
||||
(
|
||||
tag("|"),
|
||||
multispace0,
|
||||
),
|
||||
|i| term(i, d, v),
|
||||
preceded
|
||||
(
|
||||
multispace0,
|
||||
tag("|"),
|
||||
),
|
||||
),
|
||||
|x| crate::Term::absolute_value(Box::new(x)),
|
||||
)(i)
|
||||
}
|
||||
|
||||
pub(crate) fn function_or_predicate<'i, 'v, D>(i: &'i str, d: &D,
|
||||
v: &'v crate::VariableDeclarationStackLayer)
|
||||
-> IResult<&'i str, (&'i str, Option<crate::Terms>)>
|
||||
where
|
||||
D: crate::FindOrCreateFunctionDeclaration + crate::FindOrCreatePredicateDeclaration
|
||||
{
|
||||
pair
|
||||
(
|
||||
function_or_predicate_name,
|
||||
opt
|
||||
(
|
||||
delimited
|
||||
(
|
||||
delimited
|
||||
(
|
||||
multispace0,
|
||||
tag("("),
|
||||
multispace0,
|
||||
),
|
||||
separated_list0
|
||||
(
|
||||
delimited
|
||||
(
|
||||
multispace0,
|
||||
tag(","),
|
||||
multispace0,
|
||||
),
|
||||
|i| term(i, d, v),
|
||||
),
|
||||
preceded
|
||||
(
|
||||
multispace0,
|
||||
tag(")"),
|
||||
),
|
||||
)
|
||||
),
|
||||
)(i)
|
||||
}
|
||||
|
||||
fn function<'i, 'v, D>(i: &'i str, d: &D, v: &'v crate::VariableDeclarationStackLayer)
|
||||
-> IResult<&'i str, crate::Function>
|
||||
where
|
||||
D: crate::FindOrCreateFunctionDeclaration + crate::FindOrCreatePredicateDeclaration
|
||||
{
|
||||
map
|
||||
(
|
||||
|i| function_or_predicate(i, d, v),
|
||||
|(name, arguments)|
|
||||
{
|
||||
let arguments = match arguments
|
||||
{
|
||||
Some(arguments) => arguments,
|
||||
None => vec![],
|
||||
};
|
||||
|
||||
let declaration = d.find_or_create_function_declaration(name, arguments.len());
|
||||
|
||||
crate::Function::new(declaration, arguments)
|
||||
},
|
||||
)(i)
|
||||
}
|
||||
|
||||
pub(crate) fn variable_declaration(i: &str) -> IResult<&str, crate::VariableDeclaration>
|
||||
{
|
||||
map
|
||||
(
|
||||
variable_name,
|
||||
|name| crate::VariableDeclaration::new(name.to_string())
|
||||
)(i)
|
||||
}
|
||||
|
||||
fn variable<'i, 'v>(i: &'i str, v: &'v crate::VariableDeclarationStackLayer)
|
||||
-> IResult<&'i str, crate::Variable>
|
||||
{
|
||||
map
|
||||
(
|
||||
variable_name,
|
||||
|name|
|
||||
{
|
||||
let declaration = v.find_or_create(name);
|
||||
|
||||
crate::Variable::new(declaration)
|
||||
},
|
||||
)(i)
|
||||
}
|
||||
|
||||
fn term_parenthesized<'i, 'v, D>(i: &'i str, d: &D, v: &'v crate::VariableDeclarationStackLayer)
|
||||
-> IResult<&'i str, crate::Term>
|
||||
where
|
||||
D: crate::FindOrCreateFunctionDeclaration + crate::FindOrCreatePredicateDeclaration
|
||||
{
|
||||
delimited
|
||||
(
|
||||
terminated
|
||||
(
|
||||
tag("("),
|
||||
multispace0,
|
||||
),
|
||||
|i| term(i, d, v),
|
||||
preceded
|
||||
(
|
||||
multispace0,
|
||||
tag(")"),
|
||||
),
|
||||
)(i)
|
||||
}
|
||||
|
||||
fn term_precedence_0<'i, 'v, D>(i: &'i str, d: &D, v: &'v crate::VariableDeclarationStackLayer)
|
||||
-> IResult<&'i str, crate::Term>
|
||||
where
|
||||
D: crate::FindOrCreateFunctionDeclaration + crate::FindOrCreatePredicateDeclaration
|
||||
{
|
||||
alt
|
||||
((
|
||||
map
|
||||
(
|
||||
boolean,
|
||||
crate::Term::Boolean,
|
||||
),
|
||||
map
|
||||
(
|
||||
special_integer,
|
||||
crate::Term::SpecialInteger,
|
||||
),
|
||||
map
|
||||
(
|
||||
integer,
|
||||
crate::Term::Integer,
|
||||
),
|
||||
map
|
||||
(
|
||||
|i| function(i, d, v),
|
||||
crate::Term::Function,
|
||||
),
|
||||
map
|
||||
(
|
||||
string,
|
||||
crate::Term::String,
|
||||
),
|
||||
map
|
||||
(
|
||||
|i| variable(i, v),
|
||||
crate::Term::Variable,
|
||||
),
|
||||
|i| absolute_value(i, d, v),
|
||||
|i| term_parenthesized(i, d, v),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn term_precedence_1<'i, 'v, D>(i: &'i str, d: &D, v: &'v crate::VariableDeclarationStackLayer)
|
||||
-> IResult<&'i str, crate::Term>
|
||||
where
|
||||
D: crate::FindOrCreateFunctionDeclaration + crate::FindOrCreatePredicateDeclaration
|
||||
{
|
||||
alt
|
||||
((
|
||||
|i| negative(i, d, v),
|
||||
|i| term_precedence_0(i, d, v),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn term_precedence_2<'i, 'v, D>(i: &'i str, d: &D, v: &'v crate::VariableDeclarationStackLayer)
|
||||
-> IResult<&'i str, crate::Term>
|
||||
where
|
||||
D: crate::FindOrCreateFunctionDeclaration + crate::FindOrCreatePredicateDeclaration
|
||||
{
|
||||
alt
|
||||
((
|
||||
map
|
||||
(
|
||||
pair
|
||||
(
|
||||
many1
|
||||
(
|
||||
terminated
|
||||
(
|
||||
|i| term_precedence_1(i, d, v),
|
||||
delimited
|
||||
(
|
||||
multispace0,
|
||||
tag("**"),
|
||||
multispace0,
|
||||
),
|
||||
)
|
||||
),
|
||||
|i| term_precedence_1(i, d, v),
|
||||
),
|
||||
|(arguments, last_argument)| arguments.into_iter().rev().fold(last_argument,
|
||||
|accumulator, argument|
|
||||
crate::Term::exponentiate(Box::new(argument), Box::new(accumulator))),
|
||||
),
|
||||
|i| term_precedence_1(i, d, v),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn term_precedence_3<'i, 'v, D>(i: &'i str, d: &D, v: &'v crate::VariableDeclarationStackLayer)
|
||||
-> IResult<&'i str, crate::Term>
|
||||
where
|
||||
D: crate::FindOrCreateFunctionDeclaration + crate::FindOrCreatePredicateDeclaration
|
||||
{
|
||||
alt
|
||||
((
|
||||
map
|
||||
(
|
||||
pair
|
||||
(
|
||||
|i| term_precedence_2(i, d, v),
|
||||
many1
|
||||
(
|
||||
pair
|
||||
(
|
||||
delimited
|
||||
(
|
||||
multispace0,
|
||||
alt
|
||||
((
|
||||
tag("*"),
|
||||
tag("/"),
|
||||
tag("%"),
|
||||
)),
|
||||
multispace0,
|
||||
),
|
||||
|i| term_precedence_2(i, d, v),
|
||||
)
|
||||
),
|
||||
),
|
||||
|(first_argument, arguments)| arguments.into_iter().fold(first_argument,
|
||||
|accumulator, (operator, argument)|
|
||||
match operator
|
||||
{
|
||||
"*" => crate::Term::multiply(Box::new(accumulator), Box::new(argument)),
|
||||
"/" => crate::Term::divide(Box::new(accumulator), Box::new(argument)),
|
||||
"%" => crate::Term::modulo(Box::new(accumulator), Box::new(argument)),
|
||||
// TODO: handle appropriately
|
||||
_ => panic!("test"),
|
||||
})
|
||||
),
|
||||
|i| term_precedence_2(i, d, v),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn term_precedence_4<'i, 'v, D>(i: &'i str, d: &D, v: &'v crate::VariableDeclarationStackLayer)
|
||||
-> IResult<&'i str, crate::Term>
|
||||
where
|
||||
D: crate::FindOrCreateFunctionDeclaration + crate::FindOrCreatePredicateDeclaration
|
||||
{
|
||||
alt
|
||||
((
|
||||
map
|
||||
(
|
||||
pair
|
||||
(
|
||||
|i| term_precedence_3(i, d, v),
|
||||
many1
|
||||
(
|
||||
pair
|
||||
(
|
||||
delimited
|
||||
(
|
||||
multispace0,
|
||||
alt
|
||||
((
|
||||
tag("+"),
|
||||
tag("-"),
|
||||
)),
|
||||
multispace0,
|
||||
),
|
||||
|i| term_precedence_3(i, d, v),
|
||||
)
|
||||
),
|
||||
),
|
||||
|(first_argument, arguments)| arguments.into_iter().fold(first_argument,
|
||||
|accumulator, (operator, argument)|
|
||||
match operator
|
||||
{
|
||||
"+" => crate::Term::add(Box::new(accumulator), Box::new(argument)),
|
||||
"-" => crate::Term::subtract(Box::new(accumulator), Box::new(argument)),
|
||||
// TODO: handle appropriately
|
||||
_ => panic!("test"),
|
||||
})
|
||||
),
|
||||
|i| term_precedence_3(i, d, v),
|
||||
))(i)
|
||||
}
|
||||
|
||||
pub fn term<'i, 'v, D>(i: &'i str, d: &D, v: &'v crate::VariableDeclarationStackLayer)
|
||||
-> IResult<&'i str, crate::Term>
|
||||
where
|
||||
D: crate::FindOrCreateFunctionDeclaration + crate::FindOrCreatePredicateDeclaration
|
||||
{
|
||||
term_precedence_4(i, d, v)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests
|
||||
{
|
||||
use crate::{Term, VariableDeclaration, VariableDeclarationStackLayer};
|
||||
use crate::parse::terms as original;
|
||||
use crate::utils::*;
|
||||
|
||||
fn term(i: &str) -> Term
|
||||
{
|
||||
original::term(i, &Declarations::new(), &VariableDeclarationStackLayer::free()).unwrap().1
|
||||
}
|
||||
|
||||
fn format_term(i: &str) -> String
|
||||
{
|
||||
format!("{}", term(i))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_parenthesized()
|
||||
{
|
||||
assert_eq!(format_term("(1)"), format_term("1"));
|
||||
assert_eq!(format_term("((1))"), format_term("1"));
|
||||
assert_eq!(format_term("(-1)"), format_term("-1"));
|
||||
assert_eq!(format_term("((-1))"), format_term("-1"));
|
||||
assert_eq!(format_term("(-(1))"), format_term("-1"));
|
||||
assert_eq!(format_term("-((1))"), format_term("-1"));
|
||||
assert_eq!(format_term("(-(-1))"), format_term("1"));
|
||||
assert_eq!(format_term("-((-1))"), format_term("1"));
|
||||
assert_eq!(format_term("-(-(1))"), format_term("1"));
|
||||
assert_eq!(format_term("-(-(-1))"), format_term("-1"));
|
||||
assert_eq!(format_term("(a)"), format_term("a"));
|
||||
assert_eq!(format_term("((a))"), format_term("a"));
|
||||
assert_eq!(format_term("(X)"), format_term("X"));
|
||||
assert_eq!(format_term("((X))"), format_term("X"));
|
||||
assert_eq!(format_term("(\"test\")"), format_term("\"test\""));
|
||||
assert_eq!(format_term("((\"test\"))"), format_term("\"test\""));
|
||||
assert_eq!(format_term("(a ** b)"), format_term("a ** b"));
|
||||
assert_eq!(format_term("(a * b)"), format_term("a * b"));
|
||||
assert_eq!(format_term("(a / b)"), format_term("a / b"));
|
||||
assert_eq!(format_term("(a % b)"), format_term("a % b"));
|
||||
assert_eq!(format_term("(a + b)"), format_term("a + b"));
|
||||
assert_eq!(format_term("(a - b)"), format_term("a - b"));
|
||||
assert_eq!(format_term("((a ** b))"), format_term("a ** b"));
|
||||
assert_eq!(format_term("((a * b))"), format_term("a * b"));
|
||||
assert_eq!(format_term("((a / b))"), format_term("a / b"));
|
||||
assert_eq!(format_term("((a % b))"), format_term("a % b"));
|
||||
assert_eq!(format_term("((a + b))"), format_term("a + b"));
|
||||
assert_eq!(format_term("((a - b))"), format_term("a - b"));
|
||||
assert_eq!(format_term("(f(a, b))"), format_term("f(a, b)"));
|
||||
assert_eq!(format_term("((f(a, b)))"), format_term("f(a, b)"));
|
||||
assert_eq!(format_term("f((a), (b))"), format_term("f(a, b)"));
|
||||
assert_eq!(format_term("f(|-a|)"), format_term("f(|-a|)"));
|
||||
assert_eq!(format_term("f((|-a|))"), format_term("f(|-a|)"));
|
||||
assert_eq!(format_term("f((-a))"), format_term("f(-a)"));
|
||||
assert_eq!(format_term("f(((-a)))"), format_term("f(-a)"));
|
||||
assert_eq!(format_term("f((a ** b))"), format_term("f(a ** b)"));
|
||||
assert_eq!(format_term("f((a * b))"), format_term("f(a * b)"));
|
||||
assert_eq!(format_term("f((a / b))"), format_term("f(a / b)"));
|
||||
assert_eq!(format_term("f((a % b))"), format_term("f(a % b)"));
|
||||
assert_eq!(format_term("f((a + b))"), format_term("f(a + b)"));
|
||||
assert_eq!(format_term("f((a - b))"), format_term("f(a - b)"));
|
||||
assert_eq!(format_term("f(((a ** b)))"), format_term("f(a ** b)"));
|
||||
assert_eq!(format_term("f(((a * b)))"), format_term("f(a * b)"));
|
||||
assert_eq!(format_term("f(((a / b)))"), format_term("f(a / b)"));
|
||||
assert_eq!(format_term("f(((a % b)))"), format_term("f(a % b)"));
|
||||
assert_eq!(format_term("f(((a + b)))"), format_term("f(a + b)"));
|
||||
assert_eq!(format_term("f(((a - b)))"), format_term("f(a - b)"));
|
||||
assert_eq!(format_term("(|a ** b|)"), format_term("|a ** b|"));
|
||||
assert_eq!(format_term("|(a ** b)|"), format_term("|a ** b|"));
|
||||
assert_eq!(format_term("(|(a ** b)|)"), format_term("|a ** b|"));
|
||||
assert_eq!(format_term("(|a * b|)"), format_term("|a * b|"));
|
||||
assert_eq!(format_term("|(a * b)|"), format_term("|a * b|"));
|
||||
assert_eq!(format_term("(|(a * b)|)"), format_term("|a * b|"));
|
||||
assert_eq!(format_term("(|a / b|)"), format_term("|a / b|"));
|
||||
assert_eq!(format_term("|(a / b)|"), format_term("|a / b|"));
|
||||
assert_eq!(format_term("(|(a / b)|)"), format_term("|a / b|"));
|
||||
assert_eq!(format_term("(|a % b|)"), format_term("|a % b|"));
|
||||
assert_eq!(format_term("|(a % b)|"), format_term("|a % b|"));
|
||||
assert_eq!(format_term("(|(a % b)|)"), format_term("|a % b|"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_boolean()
|
||||
{
|
||||
assert_eq!(term("true"), Term::true_());
|
||||
assert_eq!(term("false"), Term::false_());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_integer()
|
||||
{
|
||||
assert_eq!(term("0"), Term::integer(0));
|
||||
assert_eq!(term("10000"), Term::integer(10000));
|
||||
assert_eq!(term("+10000"), Term::integer(10000));
|
||||
assert_eq!(term("-10000"), Term::integer(-10000));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_special_integer()
|
||||
{
|
||||
assert_eq!(term("#inf"), Term::infimum());
|
||||
assert_eq!(term("#sup"), Term::supremum());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_string()
|
||||
{
|
||||
// TODO: fix
|
||||
//assert_eq!(term("\"\""), Term::string("".to_string()));
|
||||
assert_eq!(term("\"a\""), Term::string("a".to_string()));
|
||||
assert_eq!(term("\"#\""), Term::string("#".to_string()));
|
||||
assert_eq!(term("\" \""), Term::string(" ".to_string()));
|
||||
assert_eq!(term("\" \""), Term::string(" ".to_string()));
|
||||
assert_eq!(term("\"test test\""), Term::string("test test".to_string()));
|
||||
assert_eq!(term("\"123 456\""), Term::string("123 456".to_string()));
|
||||
assert_eq!(term("\"-#? -#?\""), Term::string("-#? -#?".to_string()));
|
||||
assert_eq!(term("\"\\ntest\\n123\\n\""), Term::string("\ntest\n123\n".to_string()));
|
||||
assert_eq!(term("\"\\ttest\\t123\\t\""), Term::string("\ttest\t123\t".to_string()));
|
||||
assert_eq!(term("\"\\\\test\\\\123\\\\\""), Term::string("\\test\\123\\".to_string()));
|
||||
assert_eq!(term("\"🙂test🙂123🙂\""), Term::string("🙂test🙂123🙂".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_function()
|
||||
{
|
||||
let term_as_function = |i| match term(i)
|
||||
{
|
||||
Term::Function(function) => function,
|
||||
_ => panic!("expected function"),
|
||||
};
|
||||
|
||||
assert_eq!(term_as_function("s").declaration.name, "s");
|
||||
assert_eq!(term_as_function("s").declaration.arity, 0);
|
||||
assert!(term_as_function("s").arguments.is_empty());
|
||||
assert_eq!(term_as_function("s()").declaration.name, "s");
|
||||
assert_eq!(term_as_function("s()").declaration.arity, 0);
|
||||
assert!(term_as_function("s()").arguments.is_empty());
|
||||
assert_eq!(term_as_function("s(1, 2, 3)").declaration.name, "s");
|
||||
assert_eq!(term_as_function("s(1, 2, 3)").declaration.arity, 3);
|
||||
assert_eq!(term_as_function("s(1, 2, 3)").arguments.len(), 3);
|
||||
assert_eq!(term_as_function("s(1, 2, 3)").arguments.remove(0), Term::integer(1));
|
||||
assert_eq!(term_as_function("s(1, 2, 3)").arguments.remove(2), Term::integer(3));
|
||||
|
||||
assert_eq!(format_term("n"), "n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_variable()
|
||||
{
|
||||
let term_as_variable = |i| match term(i)
|
||||
{
|
||||
Term::Variable(variable) => variable,
|
||||
_ => panic!("expected variable"),
|
||||
};
|
||||
|
||||
assert_eq!(term_as_variable("X").declaration.name, "X");
|
||||
assert_eq!(term_as_variable("Variable_123").declaration.name, "Variable_123");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_unary()
|
||||
{
|
||||
assert_eq!(format_term("|a|"), "|a|");
|
||||
assert_eq!(format_term("||a||"), "||a||");
|
||||
assert_eq!(format_term("|a - b|"), "|a - b|");
|
||||
assert_eq!(format_term("|a| - b"), "|a| - b");
|
||||
assert_eq!(format_term("a - |b|"), "a - |b|");
|
||||
assert_eq!(format_term("||a| - b|"), "||a| - b|");
|
||||
assert_eq!(format_term("|a - |b||"), "|a - |b||");
|
||||
assert_eq!(format_term("||a| - |b||"), "||a| - |b||");
|
||||
assert_eq!(format_term("||a| - |b| - |c||"), "||a| - |b| - |c||");
|
||||
assert_eq!(format_term("||a - b| - |c - d||"), "||a - b| - |c - d||");
|
||||
assert_eq!(format_term("-a"), "-a");
|
||||
assert_eq!(format_term("--a"), "a");
|
||||
assert_eq!(format_term("---a"), "-a");
|
||||
assert_eq!(format_term("-(a + b)"), "-(a + b)");
|
||||
assert_eq!(format_term("-|a + b|"), "-|a + b|");
|
||||
assert_eq!(format_term("--|a + b|"), "|a + b|");
|
||||
assert_eq!(format_term("---|a + b|"), "-|a + b|");
|
||||
assert_eq!(term("5"), Term::integer(5));
|
||||
assert_eq!(term("-5"), Term::integer(-5));
|
||||
assert_eq!(term("--5"), Term::integer(5));
|
||||
assert_eq!(term("---5"), Term::integer(-5));
|
||||
assert_eq!(term("0"), Term::integer(0));
|
||||
assert_eq!(term("-0"), Term::integer(0));
|
||||
assert_eq!(term("--0"), Term::integer(0));
|
||||
assert_eq!(term("---0"), Term::integer(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_exponentiate()
|
||||
{
|
||||
assert_eq!(term("1 ** (2 ** (3 ** (4 ** 5)))"), term("1 ** 2 ** 3 ** 4 ** 5"));
|
||||
assert_eq!(format_term("1 ** 2 ** 3 ** 4 ** 5"), "1 ** 2 ** 3 ** 4 ** 5");
|
||||
assert_eq!(term("1 ** (2 ** (3 ** (4 ** 5)))"), term("1 ** 2 ** 3 ** 4 ** 5"));
|
||||
// As exponentiation is right-associative, these parentheses cannot be omitted
|
||||
assert_ne!(term("(((1 ** 2) ** 3) ** 4) ** 5"), term("1 ** 2 ** 3 ** 4 ** 5"));
|
||||
assert_eq!(format_term("(((1 ** 2) ** 3) ** 4) ** 5"), "(((1 ** 2) ** 3) ** 4) ** 5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_multiplicative()
|
||||
{
|
||||
assert_eq!(format_term("(a * b) * (c * d)"), "a * b * c * d");
|
||||
assert_eq!(format_term("(a * b) * (c / d)"), "a * b * c / d");
|
||||
assert_eq!(format_term("(a * b) * (c % d)"), "a * b * (c % d)");
|
||||
assert_eq!(format_term("(a / b) * (c * d)"), "a / b * c * d");
|
||||
assert_eq!(format_term("(a / b) * (c / d)"), "a / b * c / d");
|
||||
assert_eq!(format_term("(a / b) * (c % d)"), "a / b * (c % d)");
|
||||
assert_eq!(format_term("(a % b) * (c * d)"), "a % b * c * d");
|
||||
assert_eq!(format_term("(a % b) * (c / d)"), "a % b * c / d");
|
||||
assert_eq!(format_term("(a % b) * (c % d)"), "a % b * (c % d)");
|
||||
assert_eq!(format_term("(a * b) / (c * d)"), "a * b / (c * d)");
|
||||
assert_eq!(format_term("(a * b) / (c / d)"), "a * b / (c / d)");
|
||||
assert_eq!(format_term("(a * b) / (c % d)"), "a * b / (c % d)");
|
||||
assert_eq!(format_term("(a / b) / (c * d)"), "a / b / (c * d)");
|
||||
assert_eq!(format_term("(a / b) / (c / d)"), "a / b / (c / d)");
|
||||
assert_eq!(format_term("(a / b) / (c % d)"), "a / b / (c % d)");
|
||||
assert_eq!(format_term("(a % b) / (c * d)"), "a % b / (c * d)");
|
||||
assert_eq!(format_term("(a % b) / (c / d)"), "a % b / (c / d)");
|
||||
assert_eq!(format_term("(a % b) / (c % d)"), "a % b / (c % d)");
|
||||
assert_eq!(format_term("(a * b) % (c * d)"), "a * b % (c * d)");
|
||||
assert_eq!(format_term("(a * b) % (c / d)"), "a * b % (c / d)");
|
||||
assert_eq!(format_term("(a * b) % (c % d)"), "a * b % (c % d)");
|
||||
assert_eq!(format_term("(a / b) % (c * d)"), "a / b % (c * d)");
|
||||
assert_eq!(format_term("(a / b) % (c / d)"), "a / b % (c / d)");
|
||||
assert_eq!(format_term("(a / b) % (c % d)"), "a / b % (c % d)");
|
||||
assert_eq!(format_term("(a % b) % (c * d)"), "a % b % (c * d)");
|
||||
assert_eq!(format_term("(a % b) % (c / d)"), "a % b % (c / d)");
|
||||
assert_eq!(format_term("(a % b) % (c % d)"), "a % b % (c % d)");
|
||||
|
||||
// TODO: test malformed expressions
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_additive()
|
||||
{
|
||||
assert_eq!(format_term("(a + b) + (c + d)"), "a + b + c + d");
|
||||
assert_eq!(format_term("(a + b) + (c - d)"), "a + b + c - d");
|
||||
assert_eq!(format_term("(a - b) + (c + d)"), "a - b + c + d");
|
||||
assert_eq!(format_term("(a - b) + (c - d)"), "a - b + c - d");
|
||||
assert_eq!(format_term("(a + b) - (c + d)"), "a + b - (c + d)");
|
||||
assert_eq!(format_term("(a + b) - (c - d)"), "a + b - (c - d)");
|
||||
assert_eq!(format_term("(a - b) - (c + d)"), "a - b - (c + d)");
|
||||
assert_eq!(format_term("(a - b) - (c - d)"), "a - b - (c - d)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_precedence()
|
||||
{
|
||||
assert_eq!(term("-a + b"), term("(-a) + b"));
|
||||
assert_eq!(term("-a + -b"), term("(-a) + (-b)"));
|
||||
assert_eq!(term("-a + -b"), term("-(a) + -(b)"));
|
||||
assert_eq!(format_term("-(a + b)"), "-(a + b)");
|
||||
assert_eq!(term("-a - b"), term("(-a) - b"));
|
||||
assert_eq!(term("-a - -b"), term("(-a) - (-b)"));
|
||||
assert_eq!(term("-a - -b"), term("-(a) - -(b)"));
|
||||
assert_eq!(term("-a * b"), term("(-a) * b"));
|
||||
assert_eq!(term("-a * -b"), term("(-a) * (-b)"));
|
||||
assert_eq!(term("-a * -b"), term("-(a) * -(b)"));
|
||||
assert_eq!(term("-a / b"), term("(-a) / b"));
|
||||
assert_eq!(term("-a / -b"), term("(-a) / (-b)"));
|
||||
assert_eq!(term("-a / -b"), term("-(a) / -(b)"));
|
||||
assert_eq!(term("-a % b"), term("(-a) % b"));
|
||||
assert_eq!(term("-a % -b"), term("(-a) % (-b)"));
|
||||
assert_eq!(term("-a % -b"), term("-(a) % -(b)"));
|
||||
assert_eq!(term("-a ** b"), term("(-a) ** b"));
|
||||
assert_eq!(term("-a ** -b"), term("(-a) ** (-b)"));
|
||||
assert_eq!(term("-a ** -b"), term("-(a) ** -(b)"));
|
||||
assert_eq!(format_term("-(a + b)"), "-(a + b)");
|
||||
assert_eq!(format_term("-(a + b)"), "-(a + b)");
|
||||
assert_eq!(format_term("-(a + b)"), "-(a + b)");
|
||||
assert_eq!(format_term("-(a + b)"), "-(a + b)");
|
||||
assert_eq!(format_term("-(a + b)"), "-(a + b)");
|
||||
assert_eq!(term("a + (b * c) + d"), term("(a + (b * c)) + d"));
|
||||
assert_eq!(term("a + (b / c) + d"), term("(a + (b / c)) + d"));
|
||||
assert_eq!(term("a + (b % c) + d"), term("(a + (b % c)) + d"));
|
||||
assert_eq!(term("a - (b * c) - d"), term("(a - (b * c)) - d"));
|
||||
assert_eq!(term("a - (b / c) - d"), term("(a - (b / c)) - d"));
|
||||
assert_eq!(term("a - (b % c) - d"), term("(a - (b % c)) - d"));
|
||||
assert_eq!(format_term("(a + b) * (c + d)"), "(a + b) * (c + d)");
|
||||
assert_eq!(format_term("(a + b) / (c + d)"), "(a + b) / (c + d)");
|
||||
assert_eq!(format_term("(a + b) % (c + d)"), "(a + b) % (c + d)");
|
||||
assert_eq!(format_term("(a - b) * (c - d)"), "(a - b) * (c - d)");
|
||||
assert_eq!(format_term("(a - b) / (c - d)"), "(a - b) / (c - d)");
|
||||
assert_eq!(format_term("(a - b) % (c - d)"), "(a - b) % (c - d)");
|
||||
assert_eq!(term("a ** b ** c + d ** e ** f"), term("(a ** b ** c) + (d ** e ** f)"));
|
||||
assert_eq!(term("a ** (b ** c + d) ** e ** f"), term("a ** ((b ** c + d) ** (e ** f))"));
|
||||
assert_eq!(term("a ** b ** (c + d) ** e ** f"), term("a ** (b ** ((c + d) ** (e ** f)))"));
|
||||
assert_eq!(term("a ** b ** (c + d ** e) ** f"), term("a ** (b ** ((c + d ** e) ** f))"));
|
||||
assert_eq!(term("a ** b ** c - d ** e ** f"), term("(a ** b ** c) - (d ** e ** f)"));
|
||||
assert_eq!(term("a ** (b ** c - d) ** e ** f"), term("a ** ((b ** c - d) ** (e ** f))"));
|
||||
assert_eq!(term("a ** b ** (c - d) ** e ** f"), term("a ** (b ** ((c - d) ** (e ** f)))"));
|
||||
assert_eq!(term("a ** b ** (c - d ** e) ** f"), term("a ** (b ** ((c - d ** e) ** f))"));
|
||||
assert_eq!(term("a ** b ** c * d ** e ** f"), term("(a ** b ** c) * (d ** e ** f)"));
|
||||
assert_eq!(term("a ** (b ** c * d) ** e ** f"), term("a ** ((b ** c * d) ** (e ** f))"));
|
||||
assert_eq!(term("a ** b ** (c * d) ** e ** f"), term("a ** (b ** ((c * d) ** (e ** f)))"));
|
||||
assert_eq!(term("a ** b ** (c * d ** e) ** f"), term("a ** (b ** ((c * d ** e) ** f))"));
|
||||
assert_eq!(term("a ** b ** c / d ** e ** f"), term("(a ** b ** c) / (d ** e ** f)"));
|
||||
assert_eq!(term("a ** (b ** c / d) ** e ** f"), term("a ** ((b ** c / d) ** (e ** f))"));
|
||||
assert_eq!(term("a ** b ** (c / d) ** e ** f"), term("a ** (b ** ((c / d) ** (e ** f)))"));
|
||||
assert_eq!(term("a ** b ** (c / d ** e) ** f"), term("a ** (b ** ((c / d ** e) ** f))"));
|
||||
assert_eq!(term("a ** b ** c % d ** e ** f"), term("(a ** b ** c) % (d ** e ** f)"));
|
||||
assert_eq!(term("a ** (b ** c % d) ** e ** f"), term("a ** ((b ** c % d) ** (e ** f))"));
|
||||
assert_eq!(term("a ** b ** (c % d) ** e ** f"), term("a ** (b ** ((c % d) ** (e ** f)))"));
|
||||
assert_eq!(term("a ** b ** (c % d ** e) ** f"), term("a ** (b ** ((c % d ** e) ** f))"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_bounds()
|
||||
{
|
||||
let term = |i| original::term(i, &Declarations::new(),
|
||||
&VariableDeclarationStackLayer::free()).unwrap().0;
|
||||
|
||||
assert_eq!(term("1 ** 2 ** 3, rest"), ", rest");
|
||||
assert_eq!(term("1 * 2 * 3, rest"), ", rest");
|
||||
assert_eq!(term("1 / 2 / 3, rest"), ", rest");
|
||||
assert_eq!(term("1 % 2 % 3, rest"), ", rest");
|
||||
assert_eq!(term("1 + 2 + 3, rest"), ", rest");
|
||||
assert_eq!(term("1 - 2 - 3, rest"), ", rest");
|
||||
assert_eq!(term("1, rest"), ", rest");
|
||||
assert_eq!(term("-1, rest"), ", rest");
|
||||
assert_eq!(term("--1, rest"), ", rest");
|
||||
assert_eq!(term("|1|, rest"), ", rest");
|
||||
assert_eq!(term("|1| + |-2|, rest"), ", rest");
|
||||
assert_eq!(term("||-2||, rest"), ", rest");
|
||||
assert_eq!(term("|-|-2||, rest"), ", rest");
|
||||
assert_eq!(term("(1), rest"), ", rest");
|
||||
assert_eq!(term("a, rest"), ", rest");
|
||||
assert_eq!(term("1, rest"), ", rest");
|
||||
assert_eq!(term("true, rest"), ", rest");
|
||||
assert_eq!(term("false, rest"), ", rest");
|
||||
assert_eq!(term("#inf, rest"), ", rest");
|
||||
assert_eq!(term("#sup, rest"), ", rest");
|
||||
assert_eq!(term("f(1, 2), rest"), ", rest");
|
||||
assert_eq!(term("g(1 ** 2, 3 * 4, #inf), rest"), ", rest");
|
||||
assert_eq!(term("\"test\", rest"), ", rest");
|
||||
assert_eq!(term("X, rest"), ", rest");
|
||||
assert_eq!(term("Variable, rest"), ", rest");
|
||||
assert_eq!(term("f(\"test\", Variable), rest"), ", rest");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_whitespace()
|
||||
{
|
||||
assert_eq!(format_term("(a+b)*(c+d)"), "(a + b) * (c + d)");
|
||||
assert_eq!(format_term("( a + b ) * ( c + d )"), "(a + b) * (c + d)");
|
||||
assert_eq!(format_term("( a + b ) * ( c + d )"), "(a + b) * (c + d)");
|
||||
assert_eq!(format_term("(\ta\t+\tb\t)\t*\t(\tc\t+\td\t)"), "(a + b) * (c + d)");
|
||||
assert_eq!(format_term("(\na\n+\nb\n)\n*\n(\nc\n+\nd\n)"), "(a + b) * (c + d)");
|
||||
assert_eq!(format_term("( \t a \t + \t b \t ) \t * \t ( \t c \t + \t d \t )"), "(a + b) * (c + d)");
|
||||
assert_eq!(format_term("( \n a \n + \n b \n ) \n * \n ( \n c \n + \n d \n )"), "(a + b) * (c + d)");
|
||||
assert_eq!(format_term("f(\ta\t+\tb\t,\tc\t+\td\t)"), "f(a + b, c + d)");
|
||||
assert_eq!(format_term("f(\na\n+\nb\n,\nc\n+\nd\n)"), "f(a + b, c + d)");
|
||||
assert_eq!(format_term("f( \t a \t + \t b \t , \t c \t + \t d \t)"), "f(a + b, c + d)");
|
||||
assert_eq!(format_term("f( \n a \n + \n b \n , \n c \n + \n d \n)"), "f(a + b, c + d)");
|
||||
// TODO: test other operators
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_function_primitive()
|
||||
{
|
||||
let function = |i| original::function(i, &Declarations::new(),
|
||||
&VariableDeclarationStackLayer::free()).unwrap().1;
|
||||
let function_remainder = |i| original::function(i, &Declarations::new(),
|
||||
&VariableDeclarationStackLayer::free()).unwrap().0;
|
||||
|
||||
assert_eq!(function("s").declaration.name, "s");
|
||||
assert_eq!(function("s").declaration.arity, 0);
|
||||
assert_eq!(function_remainder("s"), "");
|
||||
assert_eq!(function("s ( )").declaration.name, "s");
|
||||
assert_eq!(function("s ( )").declaration.arity, 0);
|
||||
assert_eq!(function_remainder("s ( )"), "");
|
||||
assert_eq!(function("s ( 1 , 2 , 3 )").declaration.name, "s");
|
||||
assert_eq!(function("s ( 1 , 2 , 3 )").declaration.arity, 3);
|
||||
assert_eq!(function("s ( 1 , 2 , 3 )").arguments.remove(0), Term::integer(1));
|
||||
assert_eq!(function("s ( 1 , 2 , 3 )").arguments.remove(1), Term::integer(2));
|
||||
assert_eq!(function("s ( 1 , 2 , 3 )").arguments.remove(2), Term::integer(3));
|
||||
assert_eq!(function_remainder("s ( 1 , 2 , 3 )"), "");
|
||||
assert_eq!(function("s ( ), rest").declaration.name, "s");
|
||||
assert_eq!(function("s ( ), rest").declaration.arity, 0);
|
||||
assert_eq!(function_remainder("s ( ), rest"), ", rest");
|
||||
assert_eq!(function("s ( 1 , 2 , 3 ), rest").declaration.name, "s");
|
||||
assert_eq!(function("s ( 1 , 2 , 3 ), rest").declaration.arity, 3);
|
||||
assert_eq!(function_remainder("s ( 1 , 2 , 3 ), rest"), ", rest");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_variable_declaration()
|
||||
{
|
||||
let variable_declaration = |i| original::variable_declaration(i).unwrap().1;
|
||||
let variable_declaration_remainder = |i| original::variable_declaration(i).unwrap().0;
|
||||
|
||||
assert_eq!(variable_declaration("X Rest").name, "X");
|
||||
assert_eq!(variable_declaration_remainder("X Rest"), " Rest");
|
||||
assert_eq!(variable_declaration("X, Rest").name, "X");
|
||||
assert_eq!(variable_declaration_remainder("X, Rest"), ", Rest");
|
||||
// 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").name, "Variable_123");
|
||||
assert_eq!(variable_declaration_remainder("Variable_123 Rest"), " Rest");
|
||||
|
||||
let variable_declaration = original::variable_declaration;
|
||||
|
||||
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_primitive()
|
||||
{
|
||||
let variable = |i| original::variable(i, &VariableDeclarationStackLayer::free()).unwrap().1;
|
||||
let variable_remainder = |i| original::variable(i,
|
||||
&VariableDeclarationStackLayer::free()).unwrap().0;
|
||||
|
||||
assert_eq!(variable("X Rest").declaration.name, "X");
|
||||
assert_eq!(variable_remainder("X Rest"), " Rest");
|
||||
assert_eq!(variable("X, Rest").declaration.name, "X");
|
||||
assert_eq!(variable_remainder("X, Rest"), ", Rest");
|
||||
assert_eq!(variable("Variable_123 Rest").declaration.name, "Variable_123");
|
||||
assert_eq!(variable_remainder("Variable_123 Rest"), " Rest");
|
||||
|
||||
let variable = |i| original::variable(i, &VariableDeclarationStackLayer::free());
|
||||
|
||||
assert!(variable("0 Rest").is_err());
|
||||
assert!(variable("123_Asd Rest").is_err());
|
||||
assert!(variable("x Rest").is_err());
|
||||
assert!(variable("variable_123 Rest").is_err());
|
||||
assert!(variable("_ Rest").is_err());
|
||||
assert!(variable("_variable_123 Rest").is_err());
|
||||
assert!(variable(" ").is_err());
|
||||
|
||||
let new_variable_declarations = |names: &[&str]| std::rc::Rc::new(names.iter()
|
||||
.map(|name| std::rc::Rc::new(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 v_0 = VariableDeclarationStackLayer::free();
|
||||
let variable = |i| original::variable(i, &v_0).unwrap().1;
|
||||
let number_of_free_variable_declarations =
|
||||
|| v_0.free_variable_declarations_do(|x| x.len());
|
||||
|
||||
let x1 = variable("X");
|
||||
assert_eq!(number_of_free_variable_declarations(), 1);
|
||||
let x2 = variable("X");
|
||||
assert_eq!(number_of_free_variable_declarations(), 1);
|
||||
assert_eq!(x1.declaration, x2.declaration);
|
||||
let y1 = variable("Y");
|
||||
assert_eq!(number_of_free_variable_declarations(), 2);
|
||||
assert_ne!(x1.declaration, y1.declaration);
|
||||
assert_ne!(x2.declaration, y1.declaration);
|
||||
|
||||
let v_1 = VariableDeclarationStackLayer::bound(&v_0, layer_1);
|
||||
let variable = |i| original::variable(i, &v_1).unwrap().1;
|
||||
|
||||
let x3 = variable("X");
|
||||
assert_eq!(number_of_free_variable_declarations(), 2);
|
||||
assert_ne!(x1.declaration, x3.declaration);
|
||||
let x4 = variable("X");
|
||||
assert_eq!(number_of_free_variable_declarations(), 2);
|
||||
assert_eq!(x3.declaration, x4.declaration);
|
||||
let a1 = variable("A");
|
||||
assert_eq!(number_of_free_variable_declarations(), 2);
|
||||
assert_ne!(x3.declaration, a1.declaration);
|
||||
let y2 = variable("Y");
|
||||
assert_eq!(number_of_free_variable_declarations(), 2);
|
||||
assert_eq!(y1.declaration, y2.declaration);
|
||||
|
||||
let v_2 = VariableDeclarationStackLayer::bound(&v_1, layer_2);
|
||||
let variable = |i| original::variable(i, &v_2).unwrap().1;
|
||||
|
||||
let x5 = variable("X");
|
||||
assert_eq!(number_of_free_variable_declarations(), 2);
|
||||
assert_ne!(x1.declaration, x5.declaration);
|
||||
assert_ne!(x3.declaration, x5.declaration);
|
||||
let x6 = variable("X");
|
||||
assert_eq!(number_of_free_variable_declarations(), 2);
|
||||
assert_eq!(x5.declaration, x6.declaration);
|
||||
let a2 = variable("A");
|
||||
assert_eq!(number_of_free_variable_declarations(), 2);
|
||||
assert_eq!(a1.declaration, a2.declaration);
|
||||
|
||||
let v_3 = VariableDeclarationStackLayer::bound(&v_2, layer_3);
|
||||
let variable = |i| original::variable(i, &v_3).unwrap().1;
|
||||
|
||||
let x7 = variable("X");
|
||||
assert_eq!(number_of_free_variable_declarations(), 2);
|
||||
assert_eq!(x5.declaration, x7.declaration);
|
||||
let y3 = variable("Y");
|
||||
assert_eq!(number_of_free_variable_declarations(), 2);
|
||||
assert_ne!(y2.declaration, y3.declaration);
|
||||
|
||||
let v_4 = VariableDeclarationStackLayer::bound(&v_3, layer_4);
|
||||
let variable = |i| original::variable(i, &v_4).unwrap().1;
|
||||
|
||||
let x8 = variable("X");
|
||||
assert_eq!(number_of_free_variable_declarations(), 2);
|
||||
assert_ne!(x7.declaration, x8.declaration);
|
||||
let y4 = variable("Y");
|
||||
assert_eq!(number_of_free_variable_declarations(), 2);
|
||||
assert_eq!(y3.declaration, y4.declaration);
|
||||
let _ = variable("I");
|
||||
assert_eq!(number_of_free_variable_declarations(), 3);
|
||||
}
|
||||
}
|
302
src/parse/tokens.rs
Normal file
302
src/parse/tokens.rs
Normal file
@ -0,0 +1,302 @@
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub(crate) enum Symbol
|
||||
{
|
||||
ArrowLeft,
|
||||
ArrowLeftAndRight,
|
||||
ArrowRight,
|
||||
Comma,
|
||||
Division,
|
||||
Equal,
|
||||
Exponentiation,
|
||||
Greater,
|
||||
GreaterOrEqual,
|
||||
Less,
|
||||
LessOrEqual,
|
||||
Minus,
|
||||
Multiplication,
|
||||
NotEqual,
|
||||
Plus,
|
||||
VerticalBar,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Symbol
|
||||
{
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
||||
{
|
||||
match &self
|
||||
{
|
||||
Self::ArrowLeft => write!(formatter, "<-"),
|
||||
Self::ArrowLeftAndRight => write!(formatter, "<->"),
|
||||
Self::ArrowRight => write!(formatter, "->"),
|
||||
Self::Comma => write!(formatter, ","),
|
||||
Self::Division => write!(formatter, "/"),
|
||||
Self::Equal => write!(formatter, "="),
|
||||
Self::Exponentiation => write!(formatter, "**"),
|
||||
Self::Greater => write!(formatter, ">"),
|
||||
Self::GreaterOrEqual => write!(formatter, ">="),
|
||||
Self::Less => write!(formatter, "<"),
|
||||
Self::LessOrEqual => write!(formatter, "<="),
|
||||
Self::Minus => write!(formatter, "-"),
|
||||
Self::Multiplication => write!(formatter, "*"),
|
||||
Self::NotEqual => write!(formatter, "!="),
|
||||
Self::Plus => write!(formatter, "+"),
|
||||
Self::VerticalBar => write!(formatter, "|"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_identifier_start_character(character: char) -> bool
|
||||
{
|
||||
// TODO: support leading underscores
|
||||
character.is_ascii_alphabetic()
|
||||
}
|
||||
|
||||
fn is_identifier_body_character(character: char) -> bool
|
||||
{
|
||||
match character
|
||||
{
|
||||
'_' => true,
|
||||
_ if character.is_ascii_alphanumeric() => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn identifier(input: &str) -> Option<(&str, &str)>
|
||||
{
|
||||
let mut characters = input.char_indices();
|
||||
|
||||
let (_, character) = match characters.next()
|
||||
{
|
||||
Some(characters_next) => characters_next,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
if !is_identifier_start_character(character)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
loop
|
||||
{
|
||||
match characters.next()
|
||||
{
|
||||
None => return Some((input, characters.as_str())),
|
||||
Some((character_index, character)) =>
|
||||
{
|
||||
if !is_identifier_body_character(character)
|
||||
{
|
||||
return Some(input.split_at(character_index));
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn number_string(input: &str) -> Option<(&str, &str)>
|
||||
{
|
||||
let mut characters = input.char_indices();
|
||||
|
||||
let (_, character) = match characters.next()
|
||||
{
|
||||
Some(characters_next) => characters_next,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
if !character.is_ascii_digit()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
loop
|
||||
{
|
||||
match characters.next()
|
||||
{
|
||||
None => return Some((input, characters.as_str())),
|
||||
Some((character_index, character)) =>
|
||||
{
|
||||
if !character.is_ascii_digit()
|
||||
{
|
||||
return Some(input.split_at(character_index));
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn number(input: &str) -> Result<Option<(usize, &str)>, crate::parse::Error>
|
||||
{
|
||||
let (number_string, remaining_input) = match number_string(input)
|
||||
{
|
||||
Some(number_string) => number_string,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
let number = number_string.parse()
|
||||
.map_err(|error| crate::parse::Error::new_parse_number(input,
|
||||
crate::parse::error::Location::new(0, Some(0)), error))?;
|
||||
|
||||
Ok(Some((number, remaining_input)))
|
||||
}
|
||||
|
||||
pub(crate) fn symbol(input: &str) -> Option<(Symbol, &str)>
|
||||
{
|
||||
let mut characters = input.char_indices();
|
||||
|
||||
let (_, character) = match characters.next()
|
||||
{
|
||||
Some(characters_next) => characters_next,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
let remaining_input = characters.as_str();
|
||||
|
||||
match character
|
||||
{
|
||||
',' => Some((Symbol::Comma, remaining_input)),
|
||||
// <->, <-, <=, <
|
||||
'=' => Some((Symbol::Equal, remaining_input)),
|
||||
// !=
|
||||
'!' => match characters.next()
|
||||
{
|
||||
Some((_, '=')) => Some((Symbol::NotEqual, characters.as_str())),
|
||||
_ => None,
|
||||
},
|
||||
'<' => match characters.next()
|
||||
{
|
||||
Some((_, '-')) =>
|
||||
{
|
||||
let remaining_input = characters.as_str();
|
||||
|
||||
match characters.next()
|
||||
{
|
||||
Some((_, '>')) => Some((Symbol::ArrowLeftAndRight, characters.as_str())),
|
||||
_ => Some((Symbol::ArrowLeft, remaining_input)),
|
||||
}
|
||||
},
|
||||
Some((_, '=')) => Some((Symbol::LessOrEqual, characters.as_str())),
|
||||
_ => Some((Symbol::Less, remaining_input)),
|
||||
},
|
||||
// >=, >
|
||||
'>' => match characters.next()
|
||||
{
|
||||
Some((_, '=')) => Some((Symbol::GreaterOrEqual, characters.as_str())),
|
||||
_ => Some((Symbol::Greater, remaining_input)),
|
||||
},
|
||||
'+' => Some((Symbol::Plus, remaining_input)),
|
||||
// ->, -
|
||||
'-' => match characters.next()
|
||||
{
|
||||
Some((_, '>')) => Some((Symbol::ArrowRight, characters.as_str())),
|
||||
_ => Some((Symbol::Minus, remaining_input)),
|
||||
},
|
||||
// **, *
|
||||
'*' => match characters.next()
|
||||
{
|
||||
Some((_, '*')) => Some((Symbol::Exponentiation, characters.as_str())),
|
||||
_ => Some((Symbol::Multiplication, remaining_input)),
|
||||
},
|
||||
'/' => Some((Symbol::Division, remaining_input)),
|
||||
'|' => Some((Symbol::VerticalBar, remaining_input)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parenthesized_expression(input: &str)
|
||||
-> Result<Option<(&str, &str)>, crate::parse::Error>
|
||||
{
|
||||
let mut characters = input.chars();
|
||||
|
||||
let (first_character, remaining_input) = match characters.next()
|
||||
{
|
||||
Some(first_character) => (first_character, characters.as_str()),
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
if first_character != '('
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut characters = remaining_input.char_indices();
|
||||
let mut number_of_open_parentheses = 1;
|
||||
|
||||
while let Some((character_index, character)) = characters.next()
|
||||
{
|
||||
match character
|
||||
{
|
||||
'(' => number_of_open_parentheses += 1,
|
||||
')' => number_of_open_parentheses -= 1,
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if number_of_open_parentheses == 0
|
||||
{
|
||||
let position_of_closing_parenthesis = character_index;
|
||||
let (parenthesized_expression, _) =
|
||||
remaining_input.split_at(position_of_closing_parenthesis);
|
||||
let remaining_input = characters.as_str();
|
||||
|
||||
return Ok(Some((parenthesized_expression, remaining_input)));
|
||||
}
|
||||
}
|
||||
|
||||
Err(crate::parse::Error::new_unmatched_parenthesis(
|
||||
crate::parse::error::Location::new(0, Some(1))))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests
|
||||
{
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn tokenize_primitives()
|
||||
{
|
||||
assert_eq!(parenthesized_expression("(foo bar baz) test").unwrap(),
|
||||
Some(("foo bar baz", " test")));
|
||||
assert!(parenthesized_expression("( | asd#0231(asd|asd) test").is_err());
|
||||
assert_eq!(parenthesized_expression("( | asd#0231(asd|asd) ) test").unwrap(),
|
||||
Some((" | asd#0231(asd|asd) ", " test")));
|
||||
assert_eq!(parenthesized_expression("( | a)sd#0231(asd|asd) test").unwrap(),
|
||||
Some((" | a", "sd#0231(asd|asd) test")));
|
||||
|
||||
assert_eq!(number("1234, ").unwrap(), Some((1234, ", ")));
|
||||
assert_eq!(number("1234.5, ").unwrap(), Some((1234, ".5, ")));
|
||||
assert_eq!(number("-1234, ").unwrap(), None);
|
||||
assert_eq!(number("a1234, ").unwrap(), None);
|
||||
|
||||
assert_eq!(symbol("<-"), Some((Symbol::ArrowLeft, "")));
|
||||
assert_eq!(symbol("<->"), Some((Symbol::ArrowLeftAndRight, "")));
|
||||
assert_eq!(symbol("->"), Some((Symbol::ArrowRight, "")));
|
||||
assert_eq!(symbol(","), Some((Symbol::Comma, "")));
|
||||
assert_eq!(symbol("/"), Some((Symbol::Division, "")));
|
||||
assert_eq!(symbol("="), Some((Symbol::Equal, "")));
|
||||
assert_eq!(symbol("**"), Some((Symbol::Exponentiation, "")));
|
||||
assert_eq!(symbol(">"), Some((Symbol::Greater, "")));
|
||||
assert_eq!(symbol(">="), Some((Symbol::GreaterOrEqual, "")));
|
||||
assert_eq!(symbol("<"), Some((Symbol::Less, "")));
|
||||
assert_eq!(symbol("<="), Some((Symbol::LessOrEqual, "")));
|
||||
assert_eq!(symbol("-"), Some((Symbol::Minus, "")));
|
||||
assert_eq!(symbol("*"), Some((Symbol::Multiplication, "")));
|
||||
assert_eq!(symbol("!="), Some((Symbol::NotEqual, "")));
|
||||
assert_eq!(symbol("+"), Some((Symbol::Plus, "")));
|
||||
assert_eq!(symbol("|"), Some((Symbol::VerticalBar, "")));
|
||||
|
||||
assert_eq!(symbol("<-a"), Some((Symbol::ArrowLeft, "a")));
|
||||
assert_eq!(symbol("<->a"), Some((Symbol::ArrowLeftAndRight, "a")));
|
||||
assert_eq!(symbol("->a"), Some((Symbol::ArrowRight, "a")));
|
||||
assert_eq!(symbol(",a"), Some((Symbol::Comma, "a")));
|
||||
assert_eq!(symbol("/a"), Some((Symbol::Division, "a")));
|
||||
assert_eq!(symbol("=a"), Some((Symbol::Equal, "a")));
|
||||
assert_eq!(symbol("**a"), Some((Symbol::Exponentiation, "a")));
|
||||
assert_eq!(symbol(">a"), Some((Symbol::Greater, "a")));
|
||||
assert_eq!(symbol(">=a"), Some((Symbol::GreaterOrEqual, "a")));
|
||||
assert_eq!(symbol("<a"), Some((Symbol::Less, "a")));
|
||||
assert_eq!(symbol("<=a"), Some((Symbol::LessOrEqual, "a")));
|
||||
assert_eq!(symbol("-a"), Some((Symbol::Minus, "a")));
|
||||
assert_eq!(symbol("*a"), Some((Symbol::Multiplication, "a")));
|
||||
assert_eq!(symbol("!=a"), Some((Symbol::NotEqual, "a")));
|
||||
assert_eq!(symbol("+a"), Some((Symbol::Plus, "a")));
|
||||
assert_eq!(symbol("|a"), Some((Symbol::VerticalBar, "a")));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user