Implement a very basic first stab at lisp parser.
This commit is contained in:
parent
96d2cc7c6a
commit
751a3beffd
25
src/compare/error.rs
Normal file
25
src/compare/error.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
use nom::error::ErrorKind;
|
||||||
|
use nom::error::ParseError;
|
||||||
|
use nom::IResult;
|
||||||
|
|
||||||
|
pub type Res<T, U> = IResult<T, U, CustomError<T>>;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum CustomError<I> {
|
||||||
|
MyError(MyError<I>),
|
||||||
|
Nom(I, ErrorKind),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct MyError<I>(pub I);
|
||||||
|
|
||||||
|
impl<I> ParseError<I> for CustomError<I> {
|
||||||
|
fn from_error_kind(input: I, kind: ErrorKind) -> Self {
|
||||||
|
CustomError::Nom(input, kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn append(_input: I, _kind: ErrorKind, mut other: Self) -> Self {
|
||||||
|
// Doesn't do append like VerboseError
|
||||||
|
other
|
||||||
|
}
|
||||||
|
}
|
@ -1,2 +1,4 @@
|
|||||||
|
mod error;
|
||||||
mod parse;
|
mod parse;
|
||||||
|
mod sexp;
|
||||||
pub use parse::emacs_parse_org_document;
|
pub use parse::emacs_parse_org_document;
|
||||||
|
@ -1,7 +1,20 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
use crate::compare::sexp::sexp;
|
||||||
|
|
||||||
pub fn emacs_parse_org_document<'a, C>(file_path: C) -> Result<String, Box<dyn std::error::Error>>
|
pub fn emacs_parse_org_document<'a, C>(file_path: C) -> Result<String, Box<dyn std::error::Error>>
|
||||||
|
where
|
||||||
|
C: AsRef<Path>,
|
||||||
|
{
|
||||||
|
let org_sexp = emacs_parse_org_document_to_sexp(file_path)?;
|
||||||
|
let parsed_sexp = sexp(org_sexp.as_str()).expect("Parse failure");
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emacs_parse_org_document_to_sexp<'a, C>(
|
||||||
|
file_path: C,
|
||||||
|
) -> Result<String, Box<dyn std::error::Error>>
|
||||||
where
|
where
|
||||||
C: AsRef<Path>,
|
C: AsRef<Path>,
|
||||||
{
|
{
|
||||||
|
65
src/compare/sexp.rs
Normal file
65
src/compare/sexp.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use nom::branch::alt;
|
||||||
|
use nom::bytes::complete::tag;
|
||||||
|
use nom::bytes::complete::take_till1;
|
||||||
|
use nom::character::complete::multispace0;
|
||||||
|
use nom::character::complete::multispace1;
|
||||||
|
use nom::multi::separated_list1;
|
||||||
|
|
||||||
|
use super::error::Res;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Token<'s> {
|
||||||
|
Atom(&'s str),
|
||||||
|
List(Vec<Token<'s>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(ret, level = "debug")]
|
||||||
|
pub fn sexp<'s>(input: &'s str) -> Res<&'s str, Token<'s>> {
|
||||||
|
let (remaining, _) = multispace0(input)?;
|
||||||
|
let (remaining, tkn) = token(remaining)?;
|
||||||
|
let (remaining, _) = multispace0(remaining)?;
|
||||||
|
Ok((remaining, tkn))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(ret, level = "debug")]
|
||||||
|
fn token<'s>(input: &'s str) -> Res<&'s str, Token<'s>> {
|
||||||
|
alt((list, atom))(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(ret, level = "debug")]
|
||||||
|
fn list<'s>(input: &'s str) -> Res<&'s str, Token<'s>> {
|
||||||
|
let (remaining, opening_paren) = tag("(")(input)?;
|
||||||
|
let (remaining, children) = separated_list1(multispace1, token)(remaining)?;
|
||||||
|
let (remaining, closing_paren) = tag(")")(remaining)?;
|
||||||
|
Ok((remaining, Token::List(children)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(ret, level = "debug")]
|
||||||
|
fn atom<'s>(input: &'s str) -> Res<&'s str, Token<'s>> {
|
||||||
|
unquoted_atom(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(ret, level = "debug")]
|
||||||
|
fn unquoted_atom<'s>(input: &'s str) -> Res<&'s str, Token<'s>> {
|
||||||
|
let (remaining, body) = take_till1(|c| match c {
|
||||||
|
' ' | '\t' | '\r' | '\n' => true,
|
||||||
|
_ => false,
|
||||||
|
})(input)?;
|
||||||
|
Ok((remaining, Token::Atom(body)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple() {
|
||||||
|
let input = " (foo bar baz ) ";
|
||||||
|
let (remaining, parsed) = sexp(input).expect("Parse the input");
|
||||||
|
assert_eq!(remaining, "");
|
||||||
|
assert!(match parsed {
|
||||||
|
Token::Atom(_) => false,
|
||||||
|
Token::List(_) => true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user