2023-07-26 01:08:22 +00:00
|
|
|
mod date;
|
|
|
|
pub use date::Date;
|
|
|
|
|
2023-07-27 00:24:05 +00:00
|
|
|
pub mod go;
|
2023-07-26 01:08:22 +00:00
|
|
|
|
|
|
|
mod tree;
|
2023-07-26 23:33:50 +00:00
|
|
|
use tree::parse_collection;
|
2023-06-22 14:04:52 +00:00
|
|
|
|
|
|
|
use thiserror::Error;
|
|
|
|
|
2023-07-26 23:33:50 +00:00
|
|
|
#[derive(Debug)]
|
2023-07-27 00:15:22 +00:00
|
|
|
pub enum Error {
|
2023-07-26 23:33:50 +00:00
|
|
|
InvalidField,
|
|
|
|
InvalidBoardSize,
|
|
|
|
Incomplete,
|
2023-07-27 00:15:22 +00:00
|
|
|
InvalidSgf(VerboseNomError),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct VerboseNomError(nom::error::VerboseError<String>);
|
|
|
|
|
|
|
|
impl From<nom::error::VerboseError<&str>> for VerboseNomError {
|
|
|
|
fn from(err: nom::error::VerboseError<&str>) -> Self {
|
|
|
|
VerboseNomError(nom::error::VerboseError {
|
|
|
|
errors: err
|
|
|
|
.errors
|
|
|
|
.into_iter()
|
|
|
|
.map(|err| (err.0.to_owned(), err.1))
|
|
|
|
.collect(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<nom::Err<nom::error::VerboseError<&str>>> for Error {
|
|
|
|
fn from(err: nom::Err<nom::error::VerboseError<&str>>) -> Self {
|
|
|
|
match err {
|
|
|
|
nom::Err::Incomplete(_) => Error::Incomplete,
|
|
|
|
nom::Err::Error(e) => Error::InvalidSgf(VerboseNomError::from(e)),
|
|
|
|
nom::Err::Failure(e) => Error::InvalidSgf(VerboseNomError::from(e)),
|
|
|
|
}
|
|
|
|
}
|
2023-07-26 23:33:50 +00:00
|
|
|
}
|
2023-06-22 14:04:52 +00:00
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Error)]
|
|
|
|
pub enum ParseError {
|
|
|
|
#[error("An unknown error was found")]
|
2023-06-23 13:46:05 +00:00
|
|
|
NomError(nom::error::Error<String>),
|
2023-06-22 14:04:52 +00:00
|
|
|
}
|
|
|
|
|
2023-06-23 03:58:16 +00:00
|
|
|
impl From<nom::error::Error<&str>> for ParseError {
|
2023-06-23 13:46:05 +00:00
|
|
|
fn from(err: nom::error::Error<&str>) -> Self {
|
|
|
|
Self::NomError(nom::error::Error {
|
|
|
|
input: err.input.to_owned(),
|
|
|
|
code: err.code.clone(),
|
|
|
|
})
|
2023-06-23 03:58:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-26 23:33:50 +00:00
|
|
|
pub enum Game {
|
|
|
|
Go(go::Game),
|
|
|
|
Unsupported(tree::Tree),
|
|
|
|
}
|
|
|
|
|
2023-07-27 00:15:22 +00:00
|
|
|
pub fn parse_sgf(input: &str) -> Result<Vec<Game>, Error> {
|
|
|
|
let (_, trees) = parse_collection::<nom::error::VerboseError<&str>>(input)?;
|
2023-07-26 23:33:50 +00:00
|
|
|
Ok(trees
|
|
|
|
.into_iter()
|
|
|
|
.map(|t| match t.sequence[0].find_prop("GM") {
|
2023-07-27 00:24:05 +00:00
|
|
|
Some(prop) if prop.values == vec!["1".to_owned()] => {
|
|
|
|
Game::Go(go::Game::try_from(t).expect("properly structured game tree"))
|
|
|
|
}
|
2023-07-26 23:33:50 +00:00
|
|
|
_ => Game::Unsupported(t),
|
|
|
|
})
|
|
|
|
.collect::<Vec<Game>>())
|
|
|
|
}
|
|
|
|
|
2023-06-23 13:46:05 +00:00
|
|
|
/*
|
|
|
|
impl From<(&str, VerboseErrorKind)> for
|
|
|
|
|
|
|
|
impl From<nom::error::VerboseError<&str>> for ParseError {
|
|
|
|
fn from(err: nom::error::VerboseError<&str>) -> Self {
|
|
|
|
Self::NomErrors(
|
|
|
|
err.errors
|
|
|
|
.into_iter()
|
|
|
|
.map(|err| ParseError::from(err))
|
|
|
|
.collect(),
|
|
|
|
)
|
|
|
|
/*
|
|
|
|
Self::NomError(nom::error::Error {
|
|
|
|
input: err.input.to_owned(),
|
|
|
|
code: err.code.clone(),
|
|
|
|
})
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|