use regex;
use regex::Regex;
use interface::{ATermFactory, TermPlaceholder as Placeholder};
use std::result;
use std::error;
use std::fmt;
use std::borrow::Cow;
#[derive(Debug, PartialEq, Eq)]
pub struct Error {
expected: String,
offset: usize,
}
impl Error {
fn new(expected: String, offset: usize) -> Self {
Error {
expected: expected,
offset: offset,
}
}
fn from_internal_error(err: InternalError, base: &str) -> Self {
let pointer_diff = err.offset.as_ptr() as usize - base.as_ptr() as usize;
Error::new(err.expected, pointer_diff)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Expected {} at offset {}",
self.expected,
self.offset
)
}
}
struct InternalError<'a> {
expected: String,
offset: &'a str,
}
impl<'a> InternalError<'a> {
fn new(expected: String, offset: &'a str) -> Self {
InternalError {
expected: expected,
offset: offset,
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
"encountered unexpected input during parsing"
}
}
type AR<'s, F> = <F as ATermFactory<'s>>::ATermRef;
pub type Result<'t, T> = result::Result<(T, &'t str), Error>;
type InternalResult<'t, T> = result::Result<(T, &'t str), InternalError<'t>>;
pub trait ATermRead<'s>: ATermFactory<'s> {
fn read_ascii<'t: 's>(&'s self, input: &'t str) -> Result<'t, AR<'s, Self>>;
fn read_taf<'t: 's>(&'s self, input: &'t str) -> Result<'t, AR<'s, Self>>;
fn read_baf<'t: 's>(&'s self, input: &'t str) -> Result<'t, AR<'s, Self>>;
fn read_saf<'t: 's>(&'s self, input: &'t str) -> Result<'t, AR<'s, Self>>;
fn read_ascii_string<'t>(&'s self, input: &'t str) -> Result<'t, AR<'s, Self>>;
fn read_taf_string<'t>(&'s self, input: &'t str) -> Result<'t, AR<'s, Self>>;
fn read_baf_string<'t>(&'s self, input: &'t str) -> Result<'t, AR<'s, Self>>;
fn read_saf_string<'t>(&'s self, input: &'t str) -> Result<'t, AR<'s, Self>>;
}
lazy_static! {
static ref INT: Regex = Regex::new(r"^[+\-]?[0-9]+").unwrap();
static ref REAL: Regex =
Regex::new(r"^[+\-]?[0-9]+\.[0-9]*([eE][+\-]?[0-9]+)?").unwrap();
static ref CONS: Regex =
Regex::new(
concat!(r"^[A-Za-z][A-Za-z0-9_-]*|",
r#"^"([^\x00-\x08\x0A-\x1F\x7F"\\]|\\(n|t|"|\\|[0-9][0-9][0-9]))*""#))
.unwrap();
}
#[inline]
fn trim_left(string: &str) -> &str {
string.trim_left_matches(|c| '\t' <= c && c <= '\r' || c == ' ')
}
impl<'s, F> ATermRead<'s> for F
where
F: ATermFactory<'s>,
{
#[allow(unknown_lints, zero_ptr)] fn read_ascii<'t: 's>(&'s self, input: &'t str) -> Result<'t, AR<'s, F>> {
read_ascii_term(self, input)
.map_err(|e| Error::from_internal_error(e, input))
}
#[allow(unused_variables)]
fn read_taf<'t: 's>(&'s self, input: &'t str) -> Result<'t, AR<'s, F>> {
unimplemented!()
}
#[allow(unused_variables)]
fn read_baf<'t: 's>(&'s self, input: &'t str) -> Result<'t, AR<'s, F>> {
unimplemented!()
}
#[allow(unused_variables)]
fn read_saf<'t: 's>(&'s self, input: &'t str) -> Result<'t, AR<'s, F>> {
unimplemented!()
}
#[allow(unknown_lints, zero_ptr)] fn read_ascii_string<'t>(&'s self, input: &'t str) -> Result<'t, AR<'s, F>> {
read_ascii_term_string(self, input)
.map_err(|e| Error::from_internal_error(e, input))
}
#[allow(unused_variables)]
fn read_taf_string<'t>(&'s self, input: &'t str) -> Result<'t, AR<'s, F>> {
unimplemented!()
}
#[allow(unused_variables)]
fn read_baf_string<'t>(&'s self, input: &'t str) -> Result<'t, AR<'s, F>> {
unimplemented!()
}
#[allow(unused_variables)]
fn read_saf_string<'t>(&'s self, input: &'t str) -> Result<'t, AR<'s, F>> {
unimplemented!()
}
}
fn read_ascii_term<'s, 't: 's, F>(f: &'s F, input: &'t str) -> InternalResult<'t, AR<'s, F>>
where F:ATermFactory<'s>,
{
let input = input.trim_left();
if input.starts_with('<') {
read_ascii_placeholder(f, input)
} else if input.starts_with('[') {
read_list(f, input, '[', ']').map(|(v, i)| (f.list(v), i))
} else if input.starts_with('(') {
read_ascii_cons_args_annos(f, input, "")
} else if let Some(real) = REAL.find(input) {
read_ascii_annos(
f,
&input[real.end()..],
f.real(real.as_str().parse().expect("Error parsing Real")),
)
} else if let Some(int) = INT.find(input) {
read_ascii_int(f, input, int)
} else if let Some(cons) = CONS.find(input) {
read_ascii_cons_args_annos(f, &input[cons.end()..], cons.as_str())
} else {
Err(InternalError::new(
"one of '<', '[', '(', CONSTRUCTOR, INT, REAL, LONG"
.to_string(),
input
))
}
}
#[cfg_attr(rustfmt, rustfmt_skip)]
fn read_ascii_placeholder<'s, 't: 's, F>(f: &'s F, input: &'t str) -> InternalResult<'t, AR<'s, F>>
where F: ATermFactory<'s>
{
let input = trim_left(input);
if input.starts_with("<int>") {
read_ascii_annos(f, &input[5..], f.placeholder(Placeholder::Int))
} else if input.starts_with("<str>") {
read_ascii_annos(f, &input[5..], f.placeholder(Placeholder::String))
} else if input.starts_with("<real>") {
read_ascii_annos(f, &input[6..], f.placeholder(Placeholder::Real))
} else if input.starts_with("<term>") {
read_ascii_annos(f, &input[6..], f.placeholder(Placeholder::Term))
} else if input.starts_with("<appl(") {
read_list(f, &input[5..], '(', ')')
.and_then(|(v, i)| if !i.starts_with('>') {
Err(InternalError::new("'>'".to_string(), i))
} else {
read_ascii_annos(f,
&i[1..],
f.placeholder(
Placeholder::Application(
v.into_iter().collect::<Vec<_>>().into_boxed_slice())))
})
} else if input.starts_with("<list>") {
read_ascii_annos(f, &input[6..], f.placeholder(Placeholder::List))
} else if input.starts_with("<placeholder>") {
read_ascii_annos(f, &input[13..], f.placeholder(Placeholder::Placeholder))
} else if input.starts_with("<blob>") {
read_ascii_annos(f, &input[6..], f.placeholder(Placeholder::Blob))
} else if input.starts_with("<long>") {
read_ascii_annos(f, &input[6..], f.placeholder(Placeholder::Long))
} else {
Err(InternalError::new("one of 'int', 'str', 'real', 'term', 'appl', 'list', 'placeholder', \
'blob', 'long'".to_string(), input))
}
}
fn read_ascii_int<'s, 't: 's, F>(
f: &'s F,
input: &'t str,
int: regex::Match<'t>,
) -> InternalResult<'t, AR<'s, F>>
where
F: ATermFactory<'s>,
{
let after_int = &input[int.end()..];
if after_int.starts_with('l') || after_int.starts_with('L') {
read_ascii_annos(
f,
&input[(int.end() + 1)..],
f.long(int.as_str().parse().expect("Overflow on Long")),
)
} else {
read_ascii_annos(
f,
&input[int.end()..],
f.int(int.as_str().parse().expect("Overflow on Int")),
)
}
}
fn read_ascii_annos<'s, 't: 's, F>(
f: &'s F,
input: &'t str,
term: AR<'s, F>,
) -> InternalResult<'t, AR<'s, F>>
where
F: ATermFactory<'s>,
{
let input = trim_left(input);
if input.starts_with('{') {
read_list(f, input, '{', '}').map(|(v, i)| (f.with_annos(term, v), i))
} else {
Ok((term, input))
}
}
fn read_list<'s, 't: 's, F>(
f: &'s F,
input: &'t str,
start: char,
end: char,
) -> InternalResult<'t, Vec<AR<'s, F>>>
where
F: ATermFactory<'s>,
{
let input = trim_left(input);
if input.starts_with(start) {
let mut input = trim_left(&input[1..]);
let mut vec = Vec::new();
if !input.starts_with(end) {
let (term, rest_input) = read_ascii_term(f, input)?;
vec.push(term);
input = trim_left(rest_input);
while !input.starts_with(end) {
if !(input.starts_with(',')) {
return Err(InternalError::new("','".to_string(), input));
}
let (term, rest_input) = read_ascii_term(f, &input[1..])?;
vec.push(term);
input = trim_left(rest_input);
}
}
Ok((vec, &input[1..]))
} else {
Err(InternalError::new(format!("'{}'", start), input))
}
}
fn read_ascii_cons_args_annos<'s, 't: 's, S, F>(
f: &'s F,
input: &'t str,
constructor: S,
) -> InternalResult<'t, AR<'s, F>>
where
F: ATermFactory<'s>,
S: Into<Cow<'s, str>>,
{
use std::borrow::Borrow;
let constructor = constructor.into();
let input = trim_left(input);
{
let c: &str = constructor.borrow();
if c.starts_with('"') && c.ends_with('"') {
return read_ascii_qcons_args_annos(f, input, c);
}
}
if input.starts_with('(') {
read_list_string(f, input, '(', ')').and_then(|(v, i)| {
read_ascii_annos_string(f, i, f.application(constructor, v))
})
} else {
read_ascii_annos_string(f, input, f.application(constructor, ::std::iter::empty()))
}
}
fn read_ascii_qcons_args_annos<'s, 't: 's, F>(
f: &'s F,
input: &'t str,
c: &str,
) -> InternalResult<'t, AR<'s, F>>
where
F: ATermFactory<'s>,
{
use utils::string_unescape;
if input.starts_with('(') {
read_list_string(f, input, '(', ')').and_then(|(v, i)| if v.is_empty() {
read_ascii_annos_string(f, i, f.string(string_unescape(c)))
} else {
read_ascii_annos_string(f, i, f.application(String::from(c), v))
})
} else {
read_ascii_annos_string(f, input, f.string(string_unescape(c)))
}
}
fn read_ascii_term_string<'s, 't, F>(f: &'s F, input: &'t str) -> InternalResult<'t, AR<'s, F>>
where F:ATermFactory<'s>,
{
let input: &'t str = input.trim_left();
if input.starts_with('<') {
read_ascii_placeholder_string(f, input)
} else if input.starts_with('[') {
read_list_string(f, input, '[', ']').map(|(v, i)| (f.list(v), i))
} else if input.starts_with('(') {
read_ascii_cons_args_annos_string(f, input, String::new())
} else if let Some(real) = REAL.find(input) {
read_ascii_annos_string(
f,
&input[real.end()..],
f.real(real.as_str().parse().expect("Error parsing Real")),
)
} else if let Some(int) = INT.find(input) {
read_ascii_int_string(f, input, int)
} else if let Some(cons) = CONS.find(input) {
read_ascii_cons_args_annos_string(f, &input[cons.end()..], String::from(cons.as_str()))
} else {
Err(InternalError::new(
"one of '<', '[', '(', CONSTRUCTOR, INT, REAL, LONG"
.to_string(),
input
))
}
}
#[cfg_attr(rustfmt, rustfmt_skip)]
fn read_ascii_placeholder_string<'s, 't, F>(f: &'s F, input: &'t str) -> InternalResult<'t, AR<'s, F>>
where F: ATermFactory<'s>
{
let input = trim_left(input);
if input.starts_with("<int>") {
read_ascii_annos_string(f, &input[5..], f.placeholder(Placeholder::Int))
} else if input.starts_with("<str>") {
read_ascii_annos_string(f, &input[5..], f.placeholder(Placeholder::String))
} else if input.starts_with("<real>") {
read_ascii_annos_string(f, &input[6..], f.placeholder(Placeholder::Real))
} else if input.starts_with("<term>") {
read_ascii_annos_string(f, &input[6..], f.placeholder(Placeholder::Term))
} else if input.starts_with("<appl(") {
read_list_string(f, &input[5..], '(', ')')
.and_then(|(v, i)| if !i.starts_with('>') {
Err(InternalError::new("'>'".to_string(), i))
} else {
read_ascii_annos_string(f,
&i[1..],
f.placeholder(
Placeholder::Application(
v.into_iter().collect::<Vec<_>>().into_boxed_slice())))
})
} else if input.starts_with("<list>") {
read_ascii_annos_string(f, &input[6..], f.placeholder(Placeholder::List))
} else if input.starts_with("<placeholder>") {
read_ascii_annos_string(f, &input[13..], f.placeholder(Placeholder::Placeholder))
} else if input.starts_with("<blob>") {
read_ascii_annos_string(f, &input[6..], f.placeholder(Placeholder::Blob))
} else if input.starts_with("<long>") {
read_ascii_annos_string(f, &input[6..], f.placeholder(Placeholder::Long))
} else {
Err(InternalError::new("one of 'int', 'str', 'real', 'term', 'appl', 'list', 'placeholder', \
'blob', 'long'".to_string(), input))
}
}
fn read_ascii_int_string<'s, 't, F>(
f: &'s F,
input: &'t str,
int: regex::Match<'t>,
) -> InternalResult<'t, AR<'s, F>>
where
F: ATermFactory<'s>,
{
let after_int = &input[int.end()..];
if after_int.starts_with('l') || after_int.starts_with('L') {
read_ascii_annos_string(
f,
&input[(int.end() + 1)..],
f.long(int.as_str().parse().expect("Overflow on Long")),
)
} else {
read_ascii_annos_string(
f,
&input[int.end()..],
f.int(int.as_str().parse().expect("Overflow on Int")),
)
}
}
fn read_ascii_annos_string<'s, 't, F>(
f: &'s F,
input: &'t str,
term: AR<'s, F>,
) -> InternalResult<'t, AR<'s, F>>
where
F: ATermFactory<'s>,
{
let input = trim_left(input);
if input.starts_with('{') {
read_list_string(f, input, '{', '}').map(|(v, i)| (f.with_annos(term, v), i))
} else {
Ok((term, input))
}
}
fn read_list_string<'s, 't, F>(
f: &'s F,
input: &'t str,
start: char,
end: char,
) -> InternalResult<'t, Vec<AR<'s, F>>>
where
F: ATermFactory<'s>,
{
let input = trim_left(input);
if input.starts_with(start) {
let mut input = trim_left(&input[1..]);
let mut vec = Vec::new();
if !input.starts_with(end) {
let (term, rest_input) = read_ascii_term_string(f, input)?;
vec.push(term);
input = trim_left(rest_input);
while !input.starts_with(end) {
if !(input.starts_with(',')) {
return Err(InternalError::new("','".to_string(), input));
}
let (term, rest_input) = read_ascii_term_string(f, &input[1..])?;
vec.push(term);
input = trim_left(rest_input);
}
}
Ok((vec, &input[1..]))
} else {
Err(InternalError::new(format!("'{}'", start), input))
}
}
fn read_ascii_cons_args_annos_string<'s, 't, F>(
f: &'s F,
input: &'t str,
constructor: String,
) -> InternalResult<'t, AR<'s, F>>
where
F: ATermFactory<'s>,
{
use utils::string_unescape;
let input = trim_left(input);
let c = constructor;
match (
c.starts_with('"') && c.ends_with('"'),
input.starts_with('('),
) {
(true, true) => {
read_list_string(f, input, '(', ')').and_then(|(v, i)| if v.is_empty() {
read_ascii_annos_string(f, i, f.string(string_unescape(&c)))
} else {
read_ascii_annos_string(f, i, f.application(c, v))
})
}
(true, false) => read_ascii_annos_string(f, input, f.string(string_unescape(&c))),
(false, true) => {
read_list_string(f, input, '(', ')').and_then(|(v, i)| {
read_ascii_annos_string(f, i, f.application(c, v))
})
}
(false, false) => read_ascii_annos_string(f, input, f.application(c, ::std::iter::empty())),
}
}
#[cfg(test)]
mod tests {
use rc::ATermFactory;
use interface::{TermPlaceholder as Placeholder, ATermFactory as ATermFactoryT};
use parse::ATermRead;
use std::collections::hash_map::RandomState;
#[test]
fn empty_string() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
assert!(factory.read_ascii("").is_err())
}
#[test]
fn a() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let a = factory.application("a", ::std::iter::empty());
assert_eq!(factory.read_ascii("a"), Ok((a, "")))
}
#[test]
fn a_parens() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let a = factory.application("a", ::std::iter::empty());
assert_eq!(factory.read_ascii("a()"), Ok((a, "")))
}
#[test]
fn a_braces() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let a = factory.application("a", ::std::iter::empty());
assert_eq!(factory.read_ascii("a{}"), Ok((a, "")))
}
#[test]
fn a_parens_braces() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let a = factory.application("a", ::std::iter::empty());
assert_eq!(factory.read_ascii("a(){}"), Ok((a, "")))
}
#[test]
fn empty_list() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
assert_eq!(
factory.read_ascii("[]"),
Ok((factory.list(::std::iter::empty()), ""))
)
}
#[test]
fn single_element_list() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let a = factory.application("a", ::std::iter::empty());
assert_eq!(
factory.read_ascii("[a]"),
Ok((factory.list(vec![a].into_iter()), ""))
)
}
#[test]
fn two_element_list() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let a = factory.application("a", ::std::iter::empty());
assert_eq!(
factory.read_ascii("[a,a]"),
Ok((factory.list(vec![a.clone(), a].into_iter()), ""))
)
}
#[test]
fn a_ws() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let a = factory.application("a", ::std::iter::empty());
assert_eq!(factory.read_ascii(" a"), Ok((a, "")))
}
#[test]
fn a_ws_parens() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let a = factory.application("a", ::std::iter::empty());
assert_eq!(factory.read_ascii(" a ( )"), Ok((a, "")))
}
#[test]
fn a_ws_braces() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let a = factory.application("a", ::std::iter::empty());
assert_eq!(factory.read_ascii(" a { }"), Ok((a, "")))
}
#[test]
fn a_ws_parens_braces() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let a = factory.application("a", ::std::iter::empty());
assert_eq!(factory.read_ascii(" a ( ) { }"), Ok((a, "")))
}
#[test]
fn empty_list_ws() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
assert_eq!(
factory.read_ascii("[ ]"),
Ok((factory.list(::std::iter::empty()), ""))
)
}
#[test]
fn single_element_list_ws() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let a = factory.application("a", ::std::iter::empty());
assert_eq!(
factory.read_ascii("[ a ]"),
Ok((factory.list(vec![a].into_iter()), ""))
)
}
#[test]
fn two_element_list_ws() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let a = factory.application("a", ::std::iter::empty());
assert_eq!(
factory.read_ascii("[ a , a ]"),
Ok((factory.list(vec![a.clone(), a].into_iter()), ""))
)
}
#[test]
fn int() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let i = factory.int(1234567);
assert_eq!(factory.read_ascii("1234567"), Ok((i, "")))
}
#[test]
fn long() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let l = factory.long(1234567);
assert_eq!(factory.read_ascii("1234567l"), Ok((l, "")))
}
#[test]
fn string() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let s = factory.application(r#""yadda yadda \" ab12""#.to_string(), ::std::iter::empty());
assert_eq!(factory.read_ascii(r#""yadda yadda \" ab12""#), Ok((s, "")))
}
#[test]
fn placeholder() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let ip = factory.placeholder(Placeholder::Int);
assert_eq!(factory.read_ascii("<int>"), Ok((ip, "")))
}
#[test]
fn child_ordering() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let string_1 = factory.string("1");
let int = factory.application("Int", vec![string_1].into_iter());
let string_q_0 = factory.string("q_0");
let var = factory.application("Var", vec![string_q_0].into_iter());
let wld = factory.application("Wld", ::std::iter::empty());
let anno = factory.application("Anno", vec![int, wld].into_iter());
let list = factory.list(vec![anno, var].into_iter());
let string_add = factory.string("Add");
let e = factory.application("Op", vec![string_add, list]);
assert_eq!(
factory.read_ascii(r#"Op("Add",[Anno(Int("1"),Wld),Var("q_0")])"#),
Ok((e, ""))
)
}
#[test]
fn exam_example() {
let factory: ATermFactory<(), RandomState> = ATermFactory::new();
let ip = factory.placeholder(Placeholder::Int);
let sp = factory.placeholder(Placeholder::String);
let tp = factory.placeholder(Placeholder::Term);
let nine = factory.int(9);
let ap = factory.placeholder(Placeholder::Application(Box::new([tp, nine])));
let e = factory.application("exam".to_string(), vec![ap, ip, sp].into_iter());
assert_eq!(
factory.read_ascii("exam(<appl(<term>,9)>,<int>,<str>)"),
Ok((e, ""))
)
}
}