From c46b13aa92a7432865e7ac5133f3773ece832d23 Mon Sep 17 00:00:00 2001 From: C Jones Date: Wed, 19 Dec 2018 08:48:43 -0500 Subject: [PATCH] Run rustfmt --- src/lib.rs | 4 +- src/parser.rs | 967 ++++++++++++++++++++++++++++++++++---------------- src/sexp.rs | 44 ++- src/span.rs | 3 +- 4 files changed, 689 insertions(+), 329 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 792f09b..8ca3bce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,9 +3,9 @@ #![warn(missing_docs)] #![deny(unsafe_code)] +pub mod parser; pub mod sexp; pub mod span; -pub mod parser; -pub use sexp::Sexp; pub use parser::{parse, parse_one}; +pub use sexp::Sexp; diff --git a/src/parser.rs b/src/parser.rs index d03ebb5..4f7f2ef 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -13,9 +13,8 @@ //! [`parse_expression`]: fn.parse_expression.html use sexp::Sexp; -use span::{Span, ByteSpan}; +use span::{ByteSpan, Span}; - // Parsing Types /////////////////////////////////////////////////////////////// /// Represents what to do next in partially completed parsing. @@ -42,7 +41,10 @@ pub enum ParseResult<'a, T, E> { /// cause of that error. Using this, `ParseError` variants can be chained to /// produce a more complete picture of what exactly went wrong during parsing. #[derive(Debug, PartialEq, Eq, Clone)] -pub enum ParseError where Loc: Span { +pub enum ParseError +where + Loc: Span, +{ /// Parsing reached the end of input where not expecting to, usually this /// will be contained inside another `ParseError` like `String(box /// UnexpectedEof, ...)` which indicates that the closing quote was never @@ -73,7 +75,6 @@ pub enum ParseError where Loc: Span { } use self::ParseResult::*; - // Parsing Utilities /////////////////////////////////////////////////////////// trait IsDelimeter { @@ -82,12 +83,18 @@ trait IsDelimeter { impl IsDelimeter for char { fn is_delimiter(&self) -> bool { - self.is_whitespace() || *self == ';' - || *self == '(' || *self == ')' - || *self == '[' || *self == ']' - || *self == '{' || *self == '}' - || *self == '"' || *self == '\'' - || *self == '`' || *self == ',' + self.is_whitespace() + || *self == ';' + || *self == '(' + || *self == ')' + || *self == '[' + || *self == ']' + || *self == '{' + || *self == '}' + || *self == '"' + || *self == '\'' + || *self == '`' + || *self == ',' } } @@ -98,12 +105,12 @@ macro_rules! consume_whitespace { } else { return Error($ErrorFn( Box::new(ParseError::UnexpectedEof), - ($input.len(), $input.len()).offset($start_loc))); + ($input.len(), $input.len()).offset($start_loc), + )); } - } + }; } - // Top Level Parsers /////////////////////////////////////////////////////////// /// Parse a sequence of s-expressions. @@ -173,7 +180,6 @@ pub fn parse_one(input: &str) -> Result<(Sexp, &str), ParseError> { } } - // Core Parsers //////////////////////////////////////////////////////////////// // TODO: All of these parsers deserve docs, but since they're somewhat internal @@ -185,45 +191,50 @@ pub fn parse_expression(input: &str, start_loc: usize) -> ParseResult parse_number(input, start_loc), - Some('(') => parse_list(input, start_loc), + Some('(') | Some('{') | Some('[') => parse_list(input, start_loc), Some('#') => parse_character(input, start_loc), Some('"') => parse_string(input, start_loc), - Some('\'') => { - match parse_expression(&input[1..], start_loc + 1) { - Done(rest, result) => { - let span = *result.get_loc(); - let quote_span = (0, 1).offset(start_loc); - Done(rest, - Sexp::List(vec![Sexp::Sym("quote".into(), quote_span), result], - quote_span.union(&span))) - } - err => err, + Some('\'') => match parse_expression(&input[1..], start_loc + 1) { + Done(rest, result) => { + let span = *result.get_loc(); + let quote_span = (0, 1).offset(start_loc); + Done( + rest, + Sexp::List( + vec![Sexp::Sym("quote".into(), quote_span), result], + quote_span.union(&span), + ), + ) } - } - Some('`') => { - match parse_expression(&input[1..], start_loc + 1) { - Done(rest, result) => { - let span = *result.get_loc(); - let quote_span = (0, 1).offset(start_loc); - Done(rest, - Sexp::List(vec![Sexp::Sym("quasiquote".into(), quote_span), - result], - quote_span.union(&span))) - } - err => err, + err => err, + }, + Some('`') => match parse_expression(&input[1..], start_loc + 1) { + Done(rest, result) => { + let span = *result.get_loc(); + let quote_span = (0, 1).offset(start_loc); + Done( + rest, + Sexp::List( + vec![Sexp::Sym("quasiquote".into(), quote_span), result], + quote_span.union(&span), + ), + ) } - } + err => err, + }, Some(',') => { if input[1..].chars().next() == Some('@') { match parse_expression(&input[2..], start_loc + 2) { Done(rest, result) => { let span = *result.get_loc(); let quote_span = (0, 2).offset(start_loc); - Done(rest, - Sexp::List(vec![ - Sexp::Sym("unquote-splicing".into(), quote_span), - result - ], quote_span.union(&span))) + Done( + rest, + Sexp::List( + vec![Sexp::Sym("unquote-splicing".into(), quote_span), result], + quote_span.union(&span), + ), + ) } err => err, } @@ -232,11 +243,13 @@ pub fn parse_expression(input: &str, start_loc: usize) -> ParseResult { let span = *result.get_loc(); let quote_span = (0, 1).offset(start_loc); - Done(rest, - Sexp::List(vec![ - Sexp::Sym("unquote".into(), quote_span), - result - ], quote_span.union(&span))) + Done( + rest, + Sexp::List( + vec![Sexp::Sym("unquote".into(), quote_span), result], + quote_span.union(&span), + ), + ) } err => err, } @@ -251,14 +264,16 @@ pub fn parse_expression(input: &str, start_loc: usize) -> ParseResult ParseResult { let (input, start_loc) = consume_whitespace!(input, start_loc, ParseError::List); - match input.chars().nth(0) { - Some('(') => (), - Some(c) => + let first_char = match input.chars().nth(0) { + Some(c @ '(') | Some(c @ '{') | Some(c @ '[') => c, + Some(c) => { return Error(ParseError::List( Box::new(ParseError::Unexpected(c, 0)), - (0, 0).offset(start_loc))), + (0, 0).offset(start_loc), + )) + } None => unreachable!(), - } + }; let mut input = &input[1..]; let mut loc = start_loc + 1; @@ -271,9 +286,17 @@ pub fn parse_list(input: &str, start_loc: usize) -> ParseResult - return Done(&input[1..], - Sexp::List(members, (start_loc, loc+1))), + Some(c @ ')') | Some(c @ '}') | Some(c @ ']') => match (first_char, c) { + ('(', ')') | ('{', '}') | ('[', ']') => { + return Done(&input[1..], Sexp::List(members, (start_loc, loc + 1))) + } + _ => { + return Error(ParseError::List( + Box::new(ParseError::Unexpected(c, loc)), + (start_loc, loc), + )) + } + }, Some(_) => (), None => unreachable!(), } @@ -284,10 +307,7 @@ pub fn parse_list(input: &str, start_loc: usize) -> ParseResult - return Error(ParseError::List( - Box::new(err), - (0, 0).offset(loc))) + Error(err) => return Error(ParseError::List(Box::new(err), (0, 0).offset(loc))), } } } @@ -300,11 +320,15 @@ pub fn parse_number(input: &str, start_loc: usize) -> ParseResult { return Error(ParseError::Number( Box::new(ParseError::Unexpected(c, start_loc)), - (0, c.len_utf8()).offset(start_loc))); + (0, c.len_utf8()).offset(start_loc), + )); + } + None => { + return Error(ParseError::Number( + Box::new(ParseError::UnexpectedEof), + (0, 0).offset(start_loc), + )) } - None => return Error(ParseError::Number( - Box::new(ParseError::UnexpectedEof), - (0, 0).offset(start_loc))), _ => (), } @@ -319,44 +343,64 @@ pub fn parse_number(input: &str, start_loc: usize) -> ParseResult ParseResult + Some(c @ '#') | Some(c @ ':') | Some(c @ '0'...'9') => { return Error(ParseError::Symbol( Box::new(ParseError::Unexpected(c, start_loc)), - (0, 0).offset(start_loc))), - Some(c) if c.is_delimiter() => + (0, 0).offset(start_loc), + )) + } + Some(c) if c.is_delimiter() => { return Error(ParseError::Symbol( Box::new(ParseError::Unexpected(c, start_loc)), - (0, 0).offset(start_loc))), + (0, 0).offset(start_loc), + )) + } Some(_) => (), None => unreachable!(), } for (i, c) in input.char_indices() { if c.is_delimiter() { - return Done(&input[i..], - Sexp::Sym(input[..i].into(), (0, i).offset(start_loc))); + return Done( + &input[i..], + Sexp::Sym(input[..i].into(), (0, i).offset(start_loc)), + ); } } - Done(&input[input.len()..], - Sexp::Sym(input.into(), (0, input.len()).offset(start_loc))) + Done( + &input[input.len()..], + Sexp::Sym(input.into(), (0, input.len()).offset(start_loc)), + ) } #[allow(missing_docs)] @@ -393,23 +445,28 @@ pub fn parse_string(input: &str, start_loc: usize) -> ParseResult (), - Some(c) => + Some(c) => { return Error(ParseError::String( Box::new(ParseError::Unexpected(c, start_loc)), - (0, 0).offset(start_loc))), + (0, 0).offset(start_loc), + )) + } None => unreachable!(), } for (i, c) in input[1..].char_indices() { if c == '"' { - return Done(&input[2+i..], - Sexp::Str(input[1..i+1].into(), (0, i+2).offset(start_loc))); + return Done( + &input[2 + i..], + Sexp::Str(input[1..i + 1].into(), (0, i + 2).offset(start_loc)), + ); } } Error(ParseError::String( Box::new(ParseError::UnexpectedEof), - (0, input.len()).offset(start_loc))) + (0, input.len()).offset(start_loc), + )) } #[allow(missing_docs)] @@ -418,295 +475,583 @@ pub fn parse_character(input: &str, start_loc: usize) -> ParseResult (), - Some(c) => + Some(c) => { return Error(ParseError::Char( Box::new(ParseError::Unexpected(c, start_loc)), - (0, 0).offset(start_loc))), - None => + (0, 0).offset(start_loc), + )) + } + None => { return Error(ParseError::Char( Box::new(ParseError::UnexpectedEof), - (0, 0).offset(start_loc))), + (0, 0).offset(start_loc), + )) + } } match input.chars().nth(1) { Some('\\') => (), - Some(c) => + Some(c) => { return Error(ParseError::Char( Box::new(ParseError::Unexpected(c, start_loc + 1)), - (1, 1).offset(start_loc))), - None => + (1, 1).offset(start_loc), + )) + } + None => { return Error(ParseError::Char( Box::new(ParseError::UnexpectedEof), - (1, 1).offset(start_loc))) + (1, 1).offset(start_loc), + )) + } } match input.chars().nth(2) { - Some(c) => - Done(&input[3..], Sexp::Char(c, (0, 3).offset(start_loc))), - None => - Error(ParseError::Char( - Box::new(ParseError::UnexpectedEof), - (2, 2).offset(start_loc))) + Some(c) => Done(&input[3..], Sexp::Char(c, (0, 3).offset(start_loc))), + None => Error(ParseError::Char( + Box::new(ParseError::UnexpectedEof), + (2, 2).offset(start_loc), + )), } } - // Tests /////////////////////////////////////////////////////////////////////// #[cfg(test)] mod test { + use parser::ParseResult::*; + use parser::*; use sexp::Sexp; use span::Span; - use parser::*; - use parser::ParseResult::*; #[test] fn test_parse() { - assert_eq!(parse("1 2 3"), (vec![ - Sexp::Int(1, (0, 1)), Sexp::Int(2, (2, 3)), Sexp::Int(3, (4, 5)) - ], None)); - assert_eq!(parse("1 2 )"), (vec![ - Sexp::Int(1, (0, 1)), Sexp::Int(2, (2, 3)) - ], Some(ParseError::Symbol(Box::new(ParseError::Unexpected(')', 4)), (4, 4))))); + assert_eq!( + parse("1 2 3"), + ( + vec![ + Sexp::Int(1, (0, 1)), + Sexp::Int(2, (2, 3)), + Sexp::Int(3, (4, 5)) + ], + None + ) + ); + assert_eq!( + parse("1 2 )"), + ( + vec![Sexp::Int(1, (0, 1)), Sexp::Int(2, (2, 3))], + Some(ParseError::Symbol( + Box::new(ParseError::Unexpected(')', 4)), + (4, 4) + )) + ) + ); } #[test] fn test_parse_one() { - assert_eq!(parse_one("1 2"), - Ok((Sexp::Int(1, (0, 1)), " 2"))); + assert_eq!(parse_one("1 2"), Ok((Sexp::Int(1, (0, 1)), " 2"))); } #[test] fn test_parse_expression() { - assert_eq!(parse_expression(" 1", 0), - Done("", Sexp::Int(1, (1, 2)))); - assert_eq!(parse_expression("2.2", 0), - Done("", Sexp::Float(2.2, (0, 3)))); - assert_eq!(parse_expression(" a", 0), - Done("", Sexp::Sym("a".into(), (1, 2)))); - assert_eq!(parse_expression("#\\c", 0), - Done("", Sexp::Char('c', (0, 3)))); - assert_eq!(parse_expression(r#""hi""#, 0), - Done("", Sexp::Str("hi".into(), (0, 4)))); - assert_eq!(parse_expression("()", 0), - Done("", Sexp::List(vec![], (0, 2)))); - assert_eq!(parse_expression("( 1 2 3 )", 0), - Done("", Sexp::List(vec![ - Sexp::Int(1, (2, 3)), - Sexp::Int(2, (4, 5)), - Sexp::Int(3, (6, 7)), - ], (0, 9)))); - - assert_eq!(parse_expression("", 0), - Error(ParseError::Sexp(Box::new(ParseError::UnexpectedEof), (0, 0)))); + assert_eq!(parse_expression(" 1", 0), Done("", Sexp::Int(1, (1, 2)))); + assert_eq!( + parse_expression("2.2", 0), + Done("", Sexp::Float(2.2, (0, 3))) + ); + assert_eq!( + parse_expression(" a", 0), + Done("", Sexp::Sym("a".into(), (1, 2))) + ); + assert_eq!( + parse_expression("#\\c", 0), + Done("", Sexp::Char('c', (0, 3))) + ); + assert_eq!( + parse_expression(r#""hi""#, 0), + Done("", Sexp::Str("hi".into(), (0, 4))) + ); + assert_eq!( + parse_expression("()", 0), + Done("", Sexp::List(vec![], (0, 2))) + ); + assert_eq!( + parse_expression("( 1 2 3 )", 0), + Done( + "", + Sexp::List( + vec![ + Sexp::Int(1, (2, 3)), + Sexp::Int(2, (4, 5)), + Sexp::Int(3, (6, 7)), + ], + (0, 9) + ) + ) + ); + + assert_eq!( + parse_expression("", 0), + Error(ParseError::Sexp( + Box::new(ParseError::UnexpectedEof), + (0, 0) + )) + ); } #[test] fn test_parse_expr_quote() { - assert_eq!(parse_expression("'a", 0), - Done("", Sexp::List(vec![ - Sexp::Sym("quote".into(), (0, 1)), - Sexp::Sym("a".into(), (1, 2)), - ], (0, 2)))); - assert_eq!(parse_expression("'1", 0), - Done("", Sexp::List(vec![ - Sexp::Sym("quote".into(), (0, 1)), - Sexp::Int(1, (1, 2)), - ], (0, 2)))); - assert_eq!(parse_expression("' (1 2 3)", 0), - Done("", Sexp::List(vec![ - Sexp::Sym("quote".into(), (0, 1)), - Sexp::List(vec![ - Sexp::Int(1, (3, 4)), - Sexp::Int(2, (5, 6)), - Sexp::Int(3, (7, 8)), - ], (2, 9)), - ], (0, 9)))); - - assert_eq!(parse_expression("'", 0), - Error(ParseError::Sexp(Box::new(ParseError::UnexpectedEof), (1, 1)))); - assert_eq!(parse_expression("`'", 0), - Error(ParseError::Sexp(Box::new(ParseError::UnexpectedEof), (2, 2)))); + assert_eq!( + parse_expression("'a", 0), + Done( + "", + Sexp::List( + vec![ + Sexp::Sym("quote".into(), (0, 1)), + Sexp::Sym("a".into(), (1, 2)), + ], + (0, 2) + ) + ) + ); + assert_eq!( + parse_expression("'1", 0), + Done( + "", + Sexp::List( + vec![Sexp::Sym("quote".into(), (0, 1)), Sexp::Int(1, (1, 2)),], + (0, 2) + ) + ) + ); + assert_eq!( + parse_expression("' (1 2 3)", 0), + Done( + "", + Sexp::List( + vec![ + Sexp::Sym("quote".into(), (0, 1)), + Sexp::List( + vec![ + Sexp::Int(1, (3, 4)), + Sexp::Int(2, (5, 6)), + Sexp::Int(3, (7, 8)), + ], + (2, 9) + ), + ], + (0, 9) + ) + ) + ); + + assert_eq!( + parse_expression("'", 0), + Error(ParseError::Sexp( + Box::new(ParseError::UnexpectedEof), + (1, 1) + )) + ); + assert_eq!( + parse_expression("`'", 0), + Error(ParseError::Sexp( + Box::new(ParseError::UnexpectedEof), + (2, 2) + )) + ); } #[test] fn test_parse_expr_quasiquote() { - assert_eq!(parse_expression("`a", 0), - Done("", Sexp::List(vec![ - Sexp::Sym("quasiquote".into(), (0, 1)), - Sexp::Sym("a".into(), (1, 2)), - ], (0, 2)))); - assert_eq!(parse_expression("`1", 0), - Done("", Sexp::List(vec![ - Sexp::Sym("quasiquote".into(), (0, 1)), - Sexp::Int(1, (1, 2)), - ], (0, 2)))); - assert_eq!(parse_expression("` (1 2 3)", 0), - Done("", Sexp::List(vec![ - Sexp::Sym("quasiquote".into(), (0, 1)), - Sexp::List(vec![ - Sexp::Int(1, (3, 4)), - Sexp::Int(2, (5, 6)), - Sexp::Int(3, (7, 8)), - ], (2, 9)), - ], (0, 9)))); - assert_eq!(parse_expression("`'a", 0), - Done("", Sexp::List(vec![ - Sexp::Sym("quasiquote".into(), (0, 1)), - Sexp::List(vec![ - Sexp::Sym("quote".into(), (1, 2)), - Sexp::Sym("a".into(), (2, 3)), - ], (1, 3)), - ], (0, 3)))); - - assert_eq!(parse_expression("`", 0), - Error(ParseError::Sexp(Box::new(ParseError::UnexpectedEof), (1, 1)))); + assert_eq!( + parse_expression("`a", 0), + Done( + "", + Sexp::List( + vec![ + Sexp::Sym("quasiquote".into(), (0, 1)), + Sexp::Sym("a".into(), (1, 2)), + ], + (0, 2) + ) + ) + ); + assert_eq!( + parse_expression("`1", 0), + Done( + "", + Sexp::List( + vec![Sexp::Sym("quasiquote".into(), (0, 1)), Sexp::Int(1, (1, 2)),], + (0, 2) + ) + ) + ); + assert_eq!( + parse_expression("` (1 2 3)", 0), + Done( + "", + Sexp::List( + vec![ + Sexp::Sym("quasiquote".into(), (0, 1)), + Sexp::List( + vec![ + Sexp::Int(1, (3, 4)), + Sexp::Int(2, (5, 6)), + Sexp::Int(3, (7, 8)), + ], + (2, 9) + ), + ], + (0, 9) + ) + ) + ); + assert_eq!( + parse_expression("`'a", 0), + Done( + "", + Sexp::List( + vec![ + Sexp::Sym("quasiquote".into(), (0, 1)), + Sexp::List( + vec![ + Sexp::Sym("quote".into(), (1, 2)), + Sexp::Sym("a".into(), (2, 3)), + ], + (1, 3) + ), + ], + (0, 3) + ) + ) + ); + + assert_eq!( + parse_expression("`", 0), + Error(ParseError::Sexp( + Box::new(ParseError::UnexpectedEof), + (1, 1) + )) + ); } #[test] fn test_parse_expr_unquote() { - assert_eq!(parse_expression(",a", 0), - Done("", Sexp::List(vec![ - Sexp::Sym("unquote".into(), (0, 1)), - Sexp::Sym("a".into(), (1, 2)), - ], (0, 2)))); - assert_eq!(parse_expression(",1", 0), - Done("", Sexp::List(vec![ - Sexp::Sym("unquote".into(), (0, 1)), - Sexp::Int(1, (1, 2)), - ], (0, 2)))); - assert_eq!(parse_expression(", (1 2 3)", 0), - Done("", Sexp::List(vec![ - Sexp::Sym("unquote".into(), (0, 1)), - Sexp::List(vec![ - Sexp::Int(1, (3, 4)), - Sexp::Int(2, (5, 6)), - Sexp::Int(3, (7, 8)), - ], (2, 9)), - ], (0, 9)))); - assert_eq!(parse_expression("`,a", 0), - Done("", Sexp::List(vec![ - Sexp::Sym("quasiquote".into(), (0, 1)), - Sexp::List(vec![ - Sexp::Sym("unquote".into(), (1, 2)), - Sexp::Sym("a".into(), (2, 3)), - ], (1, 3)), - ], (0, 3)))); - assert_eq!(parse_expression("`(,@a)", 0), - Done("", Sexp::List(vec![ - Sexp::Sym("quasiquote".into(), (0, 1)), - Sexp::List(vec![ - Sexp::List(vec![ - Sexp::Sym("unquote-splicing".into(), (2, 4)), - Sexp::Sym("a".into(), (4, 5)), - ], (2, 5)), - ], (1, 6)), - ], (0, 6)))); - - assert_eq!(parse_expression(",", 0), - Error(ParseError::Sexp(Box::new(ParseError::UnexpectedEof), (1, 1)))); - assert_eq!(parse_expression(",@", 0), - Error(ParseError::Sexp(Box::new(ParseError::UnexpectedEof), (2, 2)))); + assert_eq!( + parse_expression(",a", 0), + Done( + "", + Sexp::List( + vec![ + Sexp::Sym("unquote".into(), (0, 1)), + Sexp::Sym("a".into(), (1, 2)), + ], + (0, 2) + ) + ) + ); + assert_eq!( + parse_expression(",1", 0), + Done( + "", + Sexp::List( + vec![Sexp::Sym("unquote".into(), (0, 1)), Sexp::Int(1, (1, 2)),], + (0, 2) + ) + ) + ); + assert_eq!( + parse_expression(", (1 2 3)", 0), + Done( + "", + Sexp::List( + vec![ + Sexp::Sym("unquote".into(), (0, 1)), + Sexp::List( + vec![ + Sexp::Int(1, (3, 4)), + Sexp::Int(2, (5, 6)), + Sexp::Int(3, (7, 8)), + ], + (2, 9) + ), + ], + (0, 9) + ) + ) + ); + assert_eq!( + parse_expression("`,a", 0), + Done( + "", + Sexp::List( + vec![ + Sexp::Sym("quasiquote".into(), (0, 1)), + Sexp::List( + vec![ + Sexp::Sym("unquote".into(), (1, 2)), + Sexp::Sym("a".into(), (2, 3)), + ], + (1, 3) + ), + ], + (0, 3) + ) + ) + ); + assert_eq!( + parse_expression("`(,@a)", 0), + Done( + "", + Sexp::List( + vec![ + Sexp::Sym("quasiquote".into(), (0, 1)), + Sexp::List( + vec![Sexp::List( + vec![ + Sexp::Sym("unquote-splicing".into(), (2, 4)), + Sexp::Sym("a".into(), (4, 5)), + ], + (2, 5) + ),], + (1, 6) + ), + ], + (0, 6) + ) + ) + ); + + assert_eq!( + parse_expression(",", 0), + Error(ParseError::Sexp( + Box::new(ParseError::UnexpectedEof), + (1, 1) + )) + ); + assert_eq!( + parse_expression(",@", 0), + Error(ParseError::Sexp( + Box::new(ParseError::UnexpectedEof), + (2, 2) + )) + ); } #[test] fn test_parse_list() { - assert_eq!(parse_list("()", 0), - Done("", Sexp::List(vec![], (0, 2)))); - assert_eq!(parse_list("(1)", 0), - Done("", Sexp::List(vec![Sexp::Int(1, (1, 2))], (0, 3)))); - assert_eq!(parse_list(" ( 1 2 3 a )", 0), Done("", Sexp::List(vec![ - Sexp::Int(1, (4, 5)), - Sexp::Int(2, (9, 10)), - Sexp::Int(3, (12, 13)), - Sexp::Sym("a".into(), (14, 15)), - ], (2, 17)))); + assert_eq!(parse_list("()", 0), Done("", Sexp::List(vec![], (0, 2)))); + assert_eq!( + parse_list("(1)", 0), + Done("", Sexp::List(vec![Sexp::Int(1, (1, 2))], (0, 3))) + ); + assert_eq!( + parse_list(" ( 1 2 3 a )", 0), + Done( + "", + Sexp::List( + vec![ + Sexp::Int(1, (4, 5)), + Sexp::Int(2, (9, 10)), + Sexp::Int(3, (12, 13)), + Sexp::Sym("a".into(), (14, 15)), + ], + (2, 17) + ) + ) + ); } #[test] fn test_parse_number() { - assert_eq!(parse_number("1", 0), - Done("", Sexp::Int(1, (0, 1)))); - assert_eq!(parse_number(" 13", 0), - Done("", Sexp::Int(13, (1, 3)))); - assert_eq!(parse_number("1.2", 0), - Done("", Sexp::Float(1.2, (0, 3)))); - assert_eq!(parse_number("\u{3000}4.2", 0), - Done("", Sexp::Float(4.2, (0, 3).offset('\u{3000}'.len_utf8())))); - assert_eq!(parse_number(" 42 ", 0), - Done(" ", Sexp::Int(42, (2, 4)))); - assert_eq!(parse_number(" 4.2 ", 0), - Done(" ", Sexp::Float(4.2, (1, 4)))); - assert_eq!(parse_number("1()", 0), - Done("()", Sexp::Int(1, (0, 1)))); - assert_eq!(parse_number("3.6()", 0), - Done("()", Sexp::Float(3.6, (0, 3)))); - - assert_eq!(parse_number("", 0), - Error(ParseError::Number(Box::new(ParseError::UnexpectedEof), (0, 0)))); - assert_eq!(parse_number("123a", 0), - Error(ParseError::Number(Box::new(ParseError::Unexpected('a', 3)), (3, 3)))); - assert_eq!(parse_number("66.6+", 0), - Error(ParseError::Number(Box::new(ParseError::Unexpected('+', 4)), (4, 4)))); + assert_eq!(parse_number("1", 0), Done("", Sexp::Int(1, (0, 1)))); + assert_eq!(parse_number(" 13", 0), Done("", Sexp::Int(13, (1, 3)))); + assert_eq!(parse_number("1.2", 0), Done("", Sexp::Float(1.2, (0, 3)))); + assert_eq!( + parse_number("\u{3000}4.2", 0), + Done("", Sexp::Float(4.2, (0, 3).offset('\u{3000}'.len_utf8()))) + ); + assert_eq!(parse_number(" 42 ", 0), Done(" ", Sexp::Int(42, (2, 4)))); + assert_eq!( + parse_number(" 4.2 ", 0), + Done(" ", Sexp::Float(4.2, (1, 4))) + ); + assert_eq!(parse_number("1()", 0), Done("()", Sexp::Int(1, (0, 1)))); + assert_eq!( + parse_number("3.6()", 0), + Done("()", Sexp::Float(3.6, (0, 3))) + ); + + assert_eq!( + parse_number("", 0), + Error(ParseError::Number( + Box::new(ParseError::UnexpectedEof), + (0, 0) + )) + ); + assert_eq!( + parse_number("123a", 0), + Error(ParseError::Number( + Box::new(ParseError::Unexpected('a', 3)), + (3, 3) + )) + ); + assert_eq!( + parse_number("66.6+", 0), + Error(ParseError::Number( + Box::new(ParseError::Unexpected('+', 4)), + (4, 4) + )) + ); } #[test] fn test_parse_ident() { - assert_eq!(parse_symbol("+", 0), - Done("", Sexp::Sym("+".into(), (0, 1)))); - assert_eq!(parse_symbol(" nil?", 0), - Done("", Sexp::Sym("nil?".into(), (1, 5)))); - assert_eq!(parse_symbol(" ->socket", 0), - Done("", Sexp::Sym("->socket".into(), (1, 9)))); - assert_eq!(parse_symbol("fib(", 0), - Done("(", Sexp::Sym("fib".into(), (0, 3)))); - assert_eq!(parse_symbol("foo2", 0), - Done("", Sexp::Sym("foo2".into(), (0, 4)))); + assert_eq!( + parse_symbol("+", 0), + Done("", Sexp::Sym("+".into(), (0, 1))) + ); + assert_eq!( + parse_symbol(" nil?", 0), + Done("", Sexp::Sym("nil?".into(), (1, 5))) + ); + assert_eq!( + parse_symbol(" ->socket", 0), + Done("", Sexp::Sym("->socket".into(), (1, 9))) + ); + assert_eq!( + parse_symbol("fib(", 0), + Done("(", Sexp::Sym("fib".into(), (0, 3))) + ); + assert_eq!( + parse_symbol("foo2", 0), + Done("", Sexp::Sym("foo2".into(), (0, 4))) + ); // We reserve #foo for the implementation to do as it wishes - assert_eq!(parse_symbol("#hi", 0), - Error(ParseError::Symbol(Box::new(ParseError::Unexpected('#', 0)), (0, 0)))); + assert_eq!( + parse_symbol("#hi", 0), + Error(ParseError::Symbol( + Box::new(ParseError::Unexpected('#', 0)), + (0, 0) + )) + ); // We reserve :foo for keywords - assert_eq!(parse_symbol(":hi", 0), - Error(ParseError::Symbol(Box::new(ParseError::Unexpected(':', 0)), (0, 0)))); - - assert_eq!(parse_symbol("", 0), - Error(ParseError::Symbol(Box::new(ParseError::UnexpectedEof), (0, 0)))); - assert_eq!(parse_symbol("0", 0), - Error(ParseError::Symbol(Box::new(ParseError::Unexpected('0', 0)), (0, 0)))); - assert_eq!(parse_symbol("()", 0), - Error(ParseError::Symbol(Box::new(ParseError::Unexpected('(', 0)), (0, 0)))); + assert_eq!( + parse_symbol(":hi", 0), + Error(ParseError::Symbol( + Box::new(ParseError::Unexpected(':', 0)), + (0, 0) + )) + ); + + assert_eq!( + parse_symbol("", 0), + Error(ParseError::Symbol( + Box::new(ParseError::UnexpectedEof), + (0, 0) + )) + ); + assert_eq!( + parse_symbol("0", 0), + Error(ParseError::Symbol( + Box::new(ParseError::Unexpected('0', 0)), + (0, 0) + )) + ); + assert_eq!( + parse_symbol("()", 0), + Error(ParseError::Symbol( + Box::new(ParseError::Unexpected('(', 0)), + (0, 0) + )) + ); } #[test] fn test_parse_string() { - assert_eq!(parse_string(r#""""#, 0), - Done("", Sexp::Str("".into(), (0, 2)))); - assert_eq!(parse_string(r#""hello""#, 0), - Done("", Sexp::Str("hello".into(), (0, 7)))); - assert_eq!(parse_string(r#" "this is a nice string -with 0123 things in it""#, 0), - Done("", Sexp::Str("this is a nice string\nwith 0123 things in it".into(), (2, 48)))); - - assert_eq!(parse_string("", 0), - Error(ParseError::String(Box::new(ParseError::UnexpectedEof), (0, 0)))); - assert_eq!(parse_string(r#""hi"#, 0), - Error(ParseError::String(Box::new(ParseError::UnexpectedEof), (0, 3)))); + assert_eq!( + parse_string(r#""""#, 0), + Done("", Sexp::Str("".into(), (0, 2))) + ); + assert_eq!( + parse_string(r#""hello""#, 0), + Done("", Sexp::Str("hello".into(), (0, 7))) + ); + assert_eq!( + parse_string( + r#" "this is a nice string +with 0123 things in it""#, + 0 + ), + Done( + "", + Sexp::Str( + "this is a nice string\nwith 0123 things in it".into(), + (2, 48) + ) + ) + ); + + assert_eq!( + parse_string("", 0), + Error(ParseError::String( + Box::new(ParseError::UnexpectedEof), + (0, 0) + )) + ); + assert_eq!( + parse_string(r#""hi"#, 0), + Error(ParseError::String( + Box::new(ParseError::UnexpectedEof), + (0, 3) + )) + ); } #[test] fn test_parse_char() { - assert_eq!(parse_character(r#"#\""#, 0), Done("", Sexp::Char('"', (0, 3)))); - assert_eq!(parse_character(r#"#\ "#, 0), Done("", Sexp::Char(' ', (0, 3)))); - assert_eq!(parse_character(r#" #\\"#, 0), Done("", Sexp::Char('\\', (2, 5)))); - - assert_eq!(parse_character("", 0), - Error(ParseError::Char(Box::new(ParseError::UnexpectedEof), (0, 0)))); - assert_eq!(parse_character("#", 0), - Error(ParseError::Char(Box::new(ParseError::UnexpectedEof), (1, 1)))); - assert_eq!(parse_character("#\\", 0), - Error(ParseError::Char(Box::new(ParseError::UnexpectedEof), (2, 2)))); - assert_eq!(parse_character("a", 0), - Error(ParseError::Char(Box::new(ParseError::Unexpected('a', 0)), (0, 0)))); + assert_eq!( + parse_character(r#"#\""#, 0), + Done("", Sexp::Char('"', (0, 3))) + ); + assert_eq!( + parse_character(r#"#\ "#, 0), + Done("", Sexp::Char(' ', (0, 3))) + ); + assert_eq!( + parse_character(r#" #\\"#, 0), + Done("", Sexp::Char('\\', (2, 5))) + ); + + assert_eq!( + parse_character("", 0), + Error(ParseError::Char( + Box::new(ParseError::UnexpectedEof), + (0, 0) + )) + ); + assert_eq!( + parse_character("#", 0), + Error(ParseError::Char( + Box::new(ParseError::UnexpectedEof), + (1, 1) + )) + ); + assert_eq!( + parse_character("#\\", 0), + Error(ParseError::Char( + Box::new(ParseError::UnexpectedEof), + (2, 2) + )) + ); + assert_eq!( + parse_character("a", 0), + Error(ParseError::Char( + Box::new(ParseError::Unexpected('a', 0)), + (0, 0) + )) + ); } } diff --git a/src/sexp.rs b/src/sexp.rs index 4f67128..4484fd3 100644 --- a/src/sexp.rs +++ b/src/sexp.rs @@ -2,14 +2,17 @@ use std::borrow::Cow; -use span::{Span, ByteSpan}; +use span::{ByteSpan, Span}; /// A type representing arbitrary s-expressions. /// /// `Sexp` carries the source code location it came from along with it for later /// diagnostic purposes. #[derive(Debug, PartialEq, Clone, PartialOrd)] -pub enum Sexp<'a, Loc=ByteSpan> where Loc: Span { +pub enum Sexp<'a, Loc = ByteSpan> +where + Loc: Span, +{ /// A value representing a symbol. Sym(Cow<'a, str>, Loc), /// A value representing a string literal. @@ -26,33 +29,46 @@ pub enum Sexp<'a, Loc=ByteSpan> where Loc: Span { List(Vec>, Loc), } -impl<'a, Loc> Sexp<'a, Loc> where Loc: Span { +impl<'a, Loc> Sexp<'a, Loc> +where + Loc: Span, +{ /// Gives a reference to the source location contained in the `Sexp`. pub fn get_loc(&self) -> &Loc { match *self { - Sexp::Sym(.., ref l) | Sexp::Str(.., ref l) | - Sexp::Char(.., ref l) | Sexp::Int(.., ref l) | - Sexp::Float(.., ref l) | Sexp::List(.., ref l) => l, + Sexp::Sym(.., ref l) + | Sexp::Str(.., ref l) + | Sexp::Char(.., ref l) + | Sexp::Int(.., ref l) + | Sexp::Float(.., ref l) + | Sexp::List(.., ref l) => l, } } /// Gives a mutable reference to the `Sexp`'s source location. pub fn get_loc_mut(&mut self) -> &mut Loc { match *self { - Sexp::Sym(.., ref mut l) | Sexp::Str(.., ref mut l) | - Sexp::Char(.., ref mut l) | Sexp::Int(.., ref mut l) | - Sexp::Float(.., ref mut l) | Sexp::List(.., ref mut l) => l, + Sexp::Sym(.., ref mut l) + | Sexp::Str(.., ref mut l) + | Sexp::Char(.., ref mut l) + | Sexp::Int(.., ref mut l) + | Sexp::Float(.., ref mut l) + | Sexp::List(.., ref mut l) => l, } } } fn extend_cow<'a, T: ?Sized>(cow: &Cow<'a, T>) -> Cow<'static, T> - where T: ToOwned +where + T: ToOwned, { Cow::Owned(cow.clone().into_owned()) } -impl<'a, Loc> Sexp<'a, Loc> where Loc: Span + Clone { +impl<'a, Loc> Sexp<'a, Loc> +where + Loc: Span + Clone, +{ /// Take ownership of an s-expression's contents. pub fn to_owned(&self) -> Sexp<'static, Loc> { match *self { @@ -61,9 +77,9 @@ impl<'a, Loc> Sexp<'a, Loc> where Loc: Span + Clone { Sexp::Char(c, ref l) => Sexp::Char(c, l.clone()), Sexp::Int(i, ref l) => Sexp::Int(i, l.clone()), Sexp::Float(f, ref l) => Sexp::Float(f, l.clone()), - Sexp::List(ref xs, ref l) => - Sexp::List(xs.iter().map(Sexp::to_owned).collect(), - l.clone()), + Sexp::List(ref xs, ref l) => { + Sexp::List(xs.iter().map(Sexp::to_owned).collect(), l.clone()) + } } } } diff --git a/src/span.rs b/src/span.rs index 3af56ac..736aaee 100644 --- a/src/span.rs +++ b/src/span.rs @@ -45,8 +45,7 @@ impl Span for ByteSpan { } fn union(&self, other: &Self) -> Self { - use std::cmp::{min, max}; + use std::cmp::{max, min}; (min(self.0, other.0), max(self.1, other.1)) } } - -- 2.47.0