]>
Witch of Git - ess/blob - src/parser.rs
1 //! Functions to parse s-expressions and expression atoms.
3 //! This module contains the core parsing machinery.
5 //! * If you're interested in getting a parsed s-expression that you can use,
6 //! then looking at [`parse`] and [`parse_one`] are your best bet.
7 //! * If you want to write your own parsers that contain s-expressions,
8 //! [`ParseResult`] and [`parse_expression`] will be the most useful to you.
10 //! [`parse`]: fn.parse.html
11 //! [`parse_one`]: fn.parse_one.html
12 //! [`ParseResult`]: enum.ParseResult.html
13 //! [`parse_expression`]: fn.parse_expression.html
16 use span
::{ByteSpan
, Span
};
19 // Parsing Types ///////////////////////////////////////////////////////////////
21 /// Represents what to do next in partially completed parsing.
23 /// `ParseResult` is returned from all intermediate parsers. If you just want to
24 /// get back parsed s-expressions, you won't need to worry about this type since
25 /// the top level parsers just return a `Result`.
27 /// If the parser failed to produce a result, it will return `Error`, and if it
28 /// succeeded we'll get the `Done` variant containing the value produced and the
29 /// rest of the text to work on.
30 #[derive(Debug, PartialEq, Eq, Clone)]
31 pub enum ParseResult
<'a
, T
, E
> {
32 /// The parser succeeded, this contains first the un-consumed portion of the
33 /// input then the result produced by parsing.
35 /// The parser failed, the `E` represents the reason for the failure.
39 /// Indicates how parsing failed.
41 /// Most `ParseError` variants contain a `Box<ParseError>` that represents the
42 /// cause of that error. Using this, `ParseError` variants can be chained to
43 /// produce a more complete picture of what exactly went wrong during parsing.
44 #[derive(Debug, PartialEq, Eq, Clone)]
45 pub enum ParseError
<Loc
= ByteSpan
>
49 /// Parsing reached the end of input where not expecting to, usually this
50 /// will be contained inside another `ParseError` like `String(box
51 /// UnexpectedEof, ...)` which indicates that the closing quote was never
54 /// Some problem occurred while parsing a list, along with the cause of that
56 List(Box
<ParseError
>, Loc
),
57 /// Some problem occurred while parsing an s-expression. This will only be
58 /// generated if EOF is reached unexpectedly at the beginning of
59 /// `parse_expression`, so it should probably be removed.
60 Sexp(Box
<ParseError
>, Loc
),
61 /// Some problem occurred while parsing a character literal, along with the
62 /// cause of the error.
63 Char(Box
<ParseError
>, Loc
),
64 /// Some problem occurred while parsing a string literal, along with the
65 /// cause of the error.
66 String(Box
<ParseError
>, Loc
),
67 /// Some problem occurred while parsing a symbol, along with the cause of
69 Symbol(Box
<ParseError
>, Loc
),
70 /// Some problem occurred while parsing a number literal, along with the
71 /// cause of the error.
72 Number(Box
<ParseError
>, Loc
),
73 /// An unexpected character was found. This will usually be the root cause
74 /// in some chain of `ParseError`s.
75 Unexpected(char, Loc
::Begin
),
77 use self::ParseResult
::*;
79 // Parsing Utilities ///////////////////////////////////////////////////////////
82 fn is_delimiter(&self) -> bool
;
85 impl IsDelimeter
for char {
86 fn is_delimiter(&self) -> bool
{
87 let delim_chars
= r
#";()[]{}"\`,"#;
88 self.is_whitespace() || delim_chars.contains(*self)
92 fn consume_whitespace<'a>(input: &'a str, start_loc: usize) -> (&'a str, usize) {
93 let mut buffer = input;
94 let mut loc = start_loc;
95 while !buffer.is_empty() && (buffer.starts_with(char::is_whitespace) || buffer.starts_with(';'))
97 if let Some(pos) = buffer.find(|c: char| !c.is_whitespace()) {
98 buffer = &buffer[pos..];
101 buffer = &buffer[buffer.len()..];
105 if buffer.starts_with(';') {
106 if let Some(pos) = buffer.find('\n') {
107 buffer = &buffer[pos + 1..];
110 buffer = &buffer[buffer.len()..];
118 macro_rules! consume_whitespace {
119 ($input:expr, $start_loc:expr, $ErrorFn:expr) => {{
120 let (text, loc) = consume_whitespace($input, $start_loc);
122 return Error($ErrorFn(Box::new(ParseError::UnexpectedEof), (loc, loc)));
129 // Top Level Parsers ///////////////////////////////////////////////////////////
131 /// Parse a sequence of s-expressions.
133 /// This function returns `(Vec<Sexp>, Option<ParseError>)` so that it can
134 /// return partial results, for when some component parses successfully and a
135 /// later part fails.
139 /// If the text contains an invalid s-expression (imbalanced parenthesis,
140 /// quotes, invalid numbers like 123q, etc.) then the parser will stop and
141 /// return an error. Every s-expression before that point that successfully
142 /// parsed will still be returned.
146 /// We can get useful partial results
149 /// # use ess::parser::parse;
150 /// let (exprs, err) = parse("1 2 3 ( 4");
151 /// assert_eq!(exprs.len(), 3);
152 /// assert!(err.is_some());
154 pub fn parse(mut input: &str) -> (Vec<Sexp>, Option<ParseError>) {
155 let mut start_loc = 0;
156 let mut results = Vec::new();
158 match parse_expression(input, start_loc) {
159 Done(rest, result) => {
160 let (rest, loc) = consume_whitespace(rest, result.get_loc().1);
163 results.push(result);
164 if rest.trim() == "" {
165 return (results, None);
169 return (results, Some(err));
175 /// Parses a single s-expression, ignoring any trailing text.
177 /// This function returns a pair of the parsed s-expression and the tail of the text.
181 /// If the text begins with an invalid s-expression (imbalanced parenthesis,
182 /// quotes, invalid numbers like 123q, etc.) then the parser will return an
183 /// error. Any text after the first s-expression doesn't affect the parsing.
189 /// # use ess::parser::parse_one;
190 /// let (expr, rest) = parse_one("1 (").unwrap();
191 /// assert_eq!(rest, " (");
193 pub fn parse_one(input: &str) -> Result<(Sexp, &str), ParseError> {
194 match parse_expression(input, 0) {
195 Done(rest, result) => Ok((result, rest)),
196 Error(err) => Err(err),
200 // Core Parsers ////////////////////////////////////////////////////////////////
202 // TODO: All of these parsers deserve docs, but since they're somewhat internal
203 // parsers, it's less critical than the rest of the API.
205 #[allow(missing_docs)]
206 pub fn parse_expression(input: &str, start_loc: usize) -> ParseResult<Sexp, ParseError> {
207 let (input, start_loc) = consume_whitespace!(input, start_loc, ParseError::Sexp);
209 match input.chars().next() {
210 Some('0'..='9') => parse_number(input, start_loc),
211 Some('(') | Some('{') | Some('[') => parse_list(input, start_loc),
212 Some('#') => parse_character(input, start_loc),
213 Some('"') => parse_string(input, start_loc),
214 Some('
\''
) => match parse_expression(&input
[1..], start_loc
+ 1) {
215 Done(rest
, result
) => {
216 let span
= *result
.get_loc();
217 let quote_span
= (0, 1).offset(start_loc
);
221 Cow
::from(vec
![Sexp
::Sym("quote".into
(), quote_span
), result
]),
222 quote_span
.un
ion
(&span
),
228 Some('`'
) => match parse_expression(&input
[1..], start_loc
+ 1) {
229 Done(rest
, result
) => {
230 let span
= *result
.get_loc();
231 let quote_span
= (0, 1).offset(start_loc
);
235 Cow
::from(vec
![Sexp
::Sym("quasiquote".into
(), quote_span
), result
]),
236 quote_span
.un
ion
(&span
),
243 if input
[1..].starts_with('@'
) {
244 match parse_expression(&input
[2..], start_loc
+ 2) {
245 Done(rest
, result
) => {
246 let span
= *result
.get_loc();
247 let quote_span
= (0, 2).offset(start_loc
);
251 Cow
::from(vec
![Sexp
::Sym("unquote-splicing".into
(), quote_span
), result
]),
252 quote_span
.un
ion
(&span
),
259 match parse_expression(&input
[1..], start_loc
+ 1) {
260 Done(rest
, result
) => {
261 let span
= *result
.get_loc();
262 let quote_span
= (0, 1).offset(start_loc
);
266 Cow
::from(vec
![Sexp
::Sym("unquote".into
(), quote_span
), result
]),
267 quote_span
.un
ion
(&span
),
275 Some(_
) => parse_symbol(input
, start_loc
),
276 None
=> unreachable
!(),
280 #[allow(missing_docs)]
281 pub fn parse_list(input
: &str, start_loc
: usize) -> ParseResult
<Sexp
, ParseError
> {
282 let (input
, start_loc
) = consume_whitespace
!(input
, start_loc
, ParseError
::List
);
284 let first_char
= match input
.chars().nth(0) {
285 Some(c @ '
('
) | Some(c @ '
{'
) | Some(c @ '
['
) => c
,
287 return Error(ParseError
::List(
288 Box
::new(ParseError
::Unexpected(c
, 0)),
289 (0, 0).offset(start_loc
),
292 None
=> unreachable
!(),
295 let mut input
= &input
[1..];
296 let mut loc
= start_loc
+ 1;
297 let mut members
= Vec
::new();
300 let (new_input
, new_loc
) = consume_whitespace
!(input
, loc
, ParseError
::List
);
305 match input
.chars().nth(0) {
306 Some(c @ '
)'
) | Some(c @ '
}'
) | Some(c @ '
]'
) => match (first_char
, c
) {
307 ('
('
, '
)'
) | ('
{'
, '
}'
) | ('
['
, '
]'
) => {
308 return Done(&input
[1..], Sexp
::List(Cow
::from(members
), (start_loc
, loc
+ 1)))
311 return Error(ParseError
::List(
312 Box
::new(ParseError
::Unexpected(c
, loc
)),
318 None
=> unreachable
!(),
321 match parse_expression(input
, loc
) {
322 Done(new_input
, member
) => {
323 loc
= member
.get_loc().1;
324 members
.push(member
);
327 Error(err
) => return Error(ParseError
::List(Box
::new(err
), (0, 0).offset(loc
))),
332 #[allow(missing_docs)]
333 pub fn parse_number(input
: &str, start_loc
: usize) -> ParseResult
<Sexp
, ParseError
> {
334 let (input
, start_loc
) = consume_whitespace
!(input
, start_loc
, ParseError
::Number
);
336 match input
.chars().next() {
337 Some(c
) if !c
.is
_d
ig
it
(10) => {
338 return Error(ParseError
::Number(
339 Box
::new(ParseError
::Unexpected(c
, start_loc
)),
340 (0, c
.len_utf8()).offset(start_loc
),
344 return Error(ParseError
::Number(
345 Box
::new(ParseError
::UnexpectedEof
),
346 (0, 0).offset(start_loc
),
355 // Before the decimal point
356 for (i
, c
) in input
.char_indices() {
362 if c
.is
_del
im
iter
() {
366 input
[..i].parse().expect("Already matched digits"),
367 (0, i
).offset(start_loc
),
372 if !c
.is
_d
ig
it
(base
) {
373 return Error(ParseError
::Number(
374 Box
::new(ParseError
::Unexpected(c
, start_loc
+ i
)),
375 (i
, i
).offset(start_loc
),
379 end
= i
+ c
.len_utf8();
382 if input
[end
..].is
_empty
() {
386 input
.parse().expect("Already matched digits"),
387 (0, end
).offset(start_loc
),
392 // After the decimal point
393 for (i
, c
) in input
[end
..].char_indices() {
394 if c
.is
_del
im
iter
() {
400 .expect("Already matched digits.digits"),
401 (0, end
+ i
).offset(start_loc
),
406 if !c
.is
_d
ig
it
(base
) {
407 return Error(ParseError
::Number(
408 Box
::new(ParseError
::Unexpected(c
, start_loc
+ i
+ end
)),
409 (i
+ end
, i
+ end
).offset(start_loc
),
415 &input
[input
.len()..],
417 input
.parse().expect("Already matched digits.digits"),
418 (0, input
.len()).offset(start_loc
),
423 #[allow(missing_docs)]
424 pub fn parse_symbol(input
: &str, start_loc
: usize) -> ParseResult
<Sexp
, ParseError
> {
425 let (input
, start_loc
) = consume_whitespace
!(input
, start_loc
, ParseError
::Symbol
);
427 match input
.chars().next() {
428 Some(c @ '
#') | Some(c @ ':') | Some(c @ '0'..='9') => {
429 return Error(ParseError
::Symbol(
430 Box
::new(ParseError
::Unexpected(c
, start_loc
)),
431 (0, 0).offset(start_loc
),
434 Some(c
) if c
.is
_del
im
iter
() => {
435 return Error(ParseError
::Symbol(
436 Box
::new(ParseError
::Unexpected(c
, start_loc
)),
437 (0, 0).offset(start_loc
),
441 None
=> unreachable
!(),
444 for (i
, c
) in input
.char_indices() {
445 if c
.is
_del
im
iter
() {
448 Sexp
::Sym(input
[..i].into
(), (0, i
).offset(start_loc
)),
454 &input
[input
.len()..],
455 Sexp
::Sym(input
.into
(), (0, input
.len()).offset(start_loc
)),
459 #[allow(missing_docs)]
460 pub fn parse_string(input
: &str, start_loc
: usize) -> ParseResult
<Sexp
, ParseError
> {
461 let (input
, start_loc
) = consume_whitespace
!(input
, start_loc
, ParseError
::String
);
463 match input
.chars().next() {
466 return Error(ParseError::String(
467 Box::new(ParseError::Unexpected(c, start_loc)),
468 (0, 0).offset(start_loc),
471 None => unreachable!(),
474 for (i, c) in input[1..].char_indices() {
478 Sexp
::Str(input
[1..=i
].into
(), (0, i
+ 2).offset(start_loc
)),
483 Error(ParseError
::String(
484 Box
::new(ParseError
::UnexpectedEof
),
485 (0, input
.len()).offset(start_loc
),
489 #[allow(missing_docs)]
490 pub fn parse_character(input
: &str, start_loc
: usize) -> ParseResult
<Sexp
, ParseError
> {
491 let (input
, start_loc
) = consume_whitespace
!(input
, start_loc
, ParseError
::Char
);
493 match input
.chars().nth(0) {
496 return Error(ParseError
::Char(
497 Box
::new(ParseError
::Unexpected(c
, start_loc
)),
498 (0, 0).offset(start_loc
),
502 return Error(ParseError
::Char(
503 Box
::new(ParseError
::UnexpectedEof
),
504 (0, 0).offset(start_loc
),
509 match input
.chars().nth(1) {
512 return Error(ParseError
::Char(
513 Box
::new(ParseError
::Unexpected(c
, start_loc
+ 1)),
514 (1, 1).offset(start_loc
),
518 return Error(ParseError
::Char(
519 Box
::new(ParseError
::UnexpectedEof
),
520 (1, 1).offset(start_loc
),
525 match input
.chars().nth(2) {
526 Some(c
) => Done(&input
[3..], Sexp
::Char(c
, (0, 3).offset(start_loc
))),
527 None
=> Error(ParseError
::Char(
528 Box
::new(ParseError
::UnexpectedEof
),
529 (2, 2).offset(start_loc
),
534 // Tests ///////////////////////////////////////////////////////////////////////
548 Sexp
::Int(1, (0, 1)),
549 Sexp
::Int(2, (2, 3)),
558 vec
![Sexp
::Int(1, (0, 1)), Sexp
::Int(2, (2, 3))],
559 Some(ParseError
::Symbol(
560 Box
::new(ParseError
::Unexpected('
)'
, 4)),
568 fn test_parse_one() {
569 assert_eq
!(parse_one("1 2"), Ok((Sexp
::Int(1, (0, 1)), " 2")));
573 fn test_parse_expression() {
574 assert_eq
!(parse_expression(" 1", 0), Done("", Sexp
::Int(1, (1, 2))));
576 parse_expression("2.2", 0),
577 Done("", Sexp
::Float(2.2, (0, 3)))
580 parse_expression(" a", 0),
581 Done("", Sexp
::Sym("a".into
(), (1, 2)))
584 parse_expression("#\\c", 0),
585 Done("", Sexp
::Char('c'
, (0, 3)))
588 parse_expression(r
#""hi""#, 0),
589 Done("", Sexp
::Str("hi".into
(), (0, 4)))
592 parse_expression("()", 0),
593 Done("", Sexp
::List(vec
![], (0, 2)))
596 parse_expression("( 1 2 3 )", 0),
601 Sexp
::Int(1, (2, 3)),
602 Sexp
::Int(2, (4, 5)),
603 Sexp
::Int(3, (6, 7)),
611 parse_expression("", 0),
612 Error(ParseError
::Sexp(
613 Box
::new(ParseError
::UnexpectedEof
),
620 fn test_parse_expr_quote() {
622 parse_expression("'a", 0),
627 Sexp
::Sym("quote".into
(), (0, 1)),
628 Sexp
::Sym("a".into
(), (1, 2)),
635 parse_expression("'1", 0),
639 vec
![Sexp
::Sym("quote".into
(), (0, 1)), Sexp
::Int(1, (1, 2)),],
645 parse_expression("' (1 2 3)", 0),
650 Sexp
::Sym("quote".into
(), (0, 1)),
653 Sexp
::Int(1, (3, 4)),
654 Sexp
::Int(2, (5, 6)),
655 Sexp
::Int(3, (7, 8)),
666 parse_expression("'", 0),
667 Error(ParseError
::Sexp(
668 Box
::new(ParseError
::UnexpectedEof
),
673 parse_expression("`'", 0),
674 Error(ParseError
::Sexp(
675 Box
::new(ParseError
::UnexpectedEof
),
682 fn test_parse_expr_quasiquote() {
684 parse_expression("`a", 0),
689 Sexp
::Sym("quasiquote".into
(), (0, 1)),
690 Sexp
::Sym("a".into
(), (1, 2)),
697 parse_expression("`1", 0),
701 vec
![Sexp
::Sym("quasiquote".into
(), (0, 1)), Sexp
::Int(1, (1, 2)),],
707 parse_expression("` (1 2 3)", 0),
712 Sexp
::Sym("quasiquote".into
(), (0, 1)),
715 Sexp
::Int(1, (3, 4)),
716 Sexp
::Int(2, (5, 6)),
717 Sexp
::Int(3, (7, 8)),
727 parse_expression("`'a", 0),
732 Sexp
::Sym("quasiquote".into
(), (0, 1)),
735 Sexp
::Sym("quote".into
(), (1, 2)),
736 Sexp
::Sym("a".into
(), (2, 3)),
747 parse_expression("`", 0),
748 Error(ParseError
::Sexp(
749 Box
::new(ParseError
::UnexpectedEof
),
756 fn test_parse_expr_unquote() {
758 parse_expression(",a", 0),
763 Sexp
::Sym("unquote".into
(), (0, 1)),
764 Sexp
::Sym("a".into
(), (1, 2)),
771 parse_expression(",1", 0),
775 vec
![Sexp
::Sym("unquote".into
(), (0, 1)), Sexp
::Int(1, (1, 2)),],
781 parse_expression(", (1 2 3)", 0),
786 Sexp
::Sym("unquote".into
(), (0, 1)),
789 Sexp
::Int(1, (3, 4)),
790 Sexp
::Int(2, (5, 6)),
791 Sexp
::Int(3, (7, 8)),
801 parse_expression("`,a", 0),
806 Sexp
::Sym("quasiquote".into
(), (0, 1)),
809 Sexp
::Sym("unquote".into
(), (1, 2)),
810 Sexp
::Sym("a".into
(), (2, 3)),
820 parse_expression("`(,@a)", 0),
825 Sexp
::Sym("quasiquote".into
(), (0, 1)),
829 Sexp
::Sym("unquote-splicing".into
(), (2, 4)),
830 Sexp
::Sym("a".into
(), (4, 5)),
843 parse_expression(",", 0),
844 Error(ParseError
::Sexp(
845 Box
::new(ParseError
::UnexpectedEof
),
850 parse_expression(",@", 0),
851 Error(ParseError
::Sexp(
852 Box
::new(ParseError
::UnexpectedEof
),
859 fn test_parse_list() {
860 assert_eq
!(parse_list("()", 0), Done("", Sexp
::List(vec
![], (0, 2))));
862 parse_list("(1)", 0),
863 Done("", Sexp
::List(vec
![Sexp
::Int(1, (1, 2))], (0, 3)))
866 parse_list(" ( 1 2 3 a )", 0),
871 Sexp
::Int(1, (4, 5)),
872 Sexp
::Int(2, (9, 10)),
873 Sexp
::Int(3, (12, 13)),
874 Sexp
::Sym("a".into
(), (14, 15)),
883 fn test_parse_number() {
884 assert_eq
!(parse_number("1", 0), Done("", Sexp
::Int(1, (0, 1))));
885 assert_eq
!(parse_number(" 13", 0), Done("", Sexp
::Int(13, (1, 3))));
886 assert_eq
!(parse_number("1.2", 0), Done("", Sexp
::Float(1.2, (0, 3))));
888 parse_number("\u{3000}4.2", 0),
889 Done("", Sexp
::Float(4.2, (0, 3).offset('
\u{3000}'
.len_utf8())))
891 assert_eq
!(parse_number(" 42 ", 0), Done(" ", Sexp
::Int(42, (2, 4))));
893 parse_number(" 4.2 ", 0),
894 Done(" ", Sexp
::Float(4.2, (1, 4)))
896 assert_eq
!(parse_number("1()", 0), Done("()", Sexp
::Int(1, (0, 1))));
898 parse_number("3.6()", 0),
899 Done("()", Sexp
::Float(3.6, (0, 3)))
904 Error(ParseError
::Number(
905 Box
::new(ParseError
::UnexpectedEof
),
910 parse_number("123a", 0),
911 Error(ParseError
::Number(
912 Box
::new(ParseError
::Unexpected('a'
, 3)),
917 parse_number("66.6+", 0),
918 Error(ParseError
::Number(
919 Box
::new(ParseError
::Unexpected('
+'
, 4)),
926 fn test_parse_ident() {
928 parse_symbol("+", 0),
929 Done("", Sexp
::Sym("+".into
(), (0, 1)))
932 parse_symbol(" nil?", 0),
933 Done("", Sexp
::Sym("nil?".into
(), (1, 5)))
936 parse_symbol(" ->socket", 0),
937 Done("", Sexp
::Sym("->socket".into
(), (1, 9)))
940 parse_symbol("fib(", 0),
941 Done("(", Sexp
::Sym("fib".into
(), (0, 3)))
944 parse_symbol("foo2", 0),
945 Done("", Sexp
::Sym("foo2".into
(), (0, 4)))
948 // We reserve #foo for the implementation to do as it wishes
950 parse_symbol("#hi", 0),
951 Error(ParseError
::Symbol(
952 Box
::new(ParseError
::Unexpected('
#', 0)),
956 // We reserve :foo for keywords
958 parse_symbol(":hi", 0),
959 Error(ParseError
::Symbol(
960 Box
::new(ParseError
::Unexpected('
:'
, 0)),
967 Error(ParseError
::Symbol(
968 Box
::new(ParseError
::UnexpectedEof
),
973 parse_symbol("0", 0),
974 Error(ParseError
::Symbol(
975 Box
::new(ParseError
::Unexpected('
0'
, 0)),
980 parse_symbol("()", 0),
981 Error(ParseError
::Symbol(
982 Box
::new(ParseError
::Unexpected('
('
, 0)),
989 fn test_parse_string() {
991 parse_string(r
#""""#, 0),
992 Done("", Sexp
::Str("".into
(), (0, 2)))
995 parse_string(r
#""hello""#, 0),
996 Done("", Sexp
::Str("hello".into
(), (0, 7)))
1000 r
#" "this is a nice string
1001 with
0123 things
in it
""#,
1007 "this is a nice string\nwith 0123 things in it".into
(),
1014 parse_string("", 0),
1015 Error(ParseError
::String(
1016 Box
::new(ParseError
::UnexpectedEof
),
1021 parse_string(r
#""hi"#, 0),
1022 Error(ParseError::String(
1023 Box::new(ParseError::UnexpectedEof),
1030 fn test_parse_char() {
1032 parse_character(r#"#\""#, 0),
1033 Done("", Sexp
::Char('
"', (0, 3)))
1036 parse_character(r#"#\ "#, 0),
1037 Done("", Sexp::Char(' ', (0, 3)))
1040 parse_character(r#" #\\"#, 0),
1041 Done("", Sexp::Char('\\', (2, 5)))
1045 parse_character("", 0),
1046 Error(ParseError::Char(
1047 Box::new(ParseError::UnexpectedEof),
1052 parse_character("#", 0),
1053 Error(ParseError::Char(
1054 Box::new(ParseError::UnexpectedEof),
1059 parse_character("#\\", 0),
1060 Error(ParseError::Char(
1061 Box::new(ParseError::UnexpectedEof),
1066 parse_character("a", 0),
1067 Error(ParseError::Char(
1068 Box::new(ParseError::Unexpected('a', 0)),
1075 fn test_parse_comments() {
1080 ;hey
;how are you doing?
1083 (vec![Sexp::List(vec![], (0, 42))], None)