]> Witch of Git - ess/blob - src/parser.rs
Code cleanup
[ess] / src / parser.rs
1 //! Functions to parse s-expressions and expression atoms.
2 //!
3 //! This module contains the core parsing machinery.
4 //!
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.
9 //!
10 //! [`parse`]: fn.parse.html
11 //! [`parse_one`]: fn.parse_one.html
12 //! [`ParseResult`]: enum.ParseResult.html
13 //! [`parse_expression`]: fn.parse_expression.html
14
15 use sexp::Sexp;
16 use span::{ByteSpan, Span};
17
18 // Parsing Types ///////////////////////////////////////////////////////////////
19
20 /// Represents what to do next in partially completed parsing.
21 ///
22 /// `ParseResult` is returned from all intermediate parsers. If you just want to
23 /// get back parsed s-expressions, you won't need to worry about this type since
24 /// the top level parsers just return a `Result`.
25 ///
26 /// If the parser failed to produce a result, it will return `Error`, and if it
27 /// succeeded we'll get the `Done` variant containing the value produced and the
28 /// rest of the text to work on.
29 #[derive(Debug, PartialEq, Eq, Clone)]
30 pub enum ParseResult<'a, T, E> {
31 /// The parser succeeded, this contains first the un-consumed portion of the
32 /// input then the result produced by parsing.
33 Done(&'a str, T),
34 /// The parser failed, the `E` represents the reason for the failure.
35 Error(E),
36 }
37
38 /// Indicates how parsing failed.
39 ///
40 /// Most `ParseError` variants contain a `Box<ParseError>` that represents the
41 /// cause of that error. Using this, `ParseError` variants can be chained to
42 /// produce a more complete picture of what exactly went wrong during parsing.
43 #[derive(Debug, PartialEq, Eq, Clone)]
44 pub enum ParseError<Loc = ByteSpan>
45 where
46 Loc: Span,
47 {
48 /// Parsing reached the end of input where not expecting to, usually this
49 /// will be contained inside another `ParseError` like `String(box
50 /// UnexpectedEof, ...)` which indicates that the closing quote was never
51 /// found.
52 UnexpectedEof,
53 /// Some problem occurred while parsing a list, along with the cause of that
54 /// error.
55 List(Box<ParseError>, Loc),
56 /// Some problem occurred while parsing an s-expression. This will only be
57 /// generated if EOF is reached unexpectedly at the beginning of
58 /// `parse_expression`, so it should probably be removed.
59 Sexp(Box<ParseError>, Loc),
60 /// Some problem occurred while parsing a character literal, along with the
61 /// cause of the error.
62 Char(Box<ParseError>, Loc),
63 /// Some problem occurred while parsing a string literal, along with the
64 /// cause of the error.
65 String(Box<ParseError>, Loc),
66 /// Some problem occurred while parsing a symbol, along with the cause of
67 /// the error.
68 Symbol(Box<ParseError>, Loc),
69 /// Some problem occurred while parsing a number literal, along with the
70 /// cause of the error.
71 Number(Box<ParseError>, Loc),
72 /// An unexpected character was found. This will usually be the root cause
73 /// in some chain of `ParseError`s.
74 Unexpected(char, Loc::Begin),
75 }
76 use self::ParseResult::*;
77
78 // Parsing Utilities ///////////////////////////////////////////////////////////
79
80 trait IsDelimeter {
81 fn is_delimiter(&self) -> bool;
82 }
83
84 impl IsDelimeter for char {
85 fn is_delimiter(&self) -> bool {
86 let delim_chars = r#";()[]{}"\`,"#;
87 self.is_whitespace() || delim_chars.contains(*self)
88 }
89 }
90
91 macro_rules! consume_whitespace {
92 ($input:expr, $start_loc:expr, $ErrorFn:expr) => {
93 if let Some(pos) = $input.find(|c: char| !c.is_whitespace()) {
94 (&$input[pos..], $start_loc + pos)
95 } else {
96 return Error($ErrorFn(
97 Box::new(ParseError::UnexpectedEof),
98 ($input.len(), $input.len()).offset($start_loc),
99 ));
100 }
101 };
102 }
103
104 // Top Level Parsers ///////////////////////////////////////////////////////////
105
106 /// Parse a sequence of s-expressions.
107 ///
108 /// This function returns `(Vec<Sexp>, Option<ParseError>)` so that it can
109 /// return partial results, for when some component parses successfully and a
110 /// later part fails.
111 ///
112 /// # Errors
113 ///
114 /// If the text contains an invalid s-expression (imbalanced parenthesis,
115 /// quotes, invalid numbers like 123q, etc.) then the parser will stop and
116 /// return an error. Every s-expression before that point that successfully
117 /// parsed will still be returned.
118 ///
119 /// # Examples
120 ///
121 /// We can get useful partial results
122 ///
123 /// ```rust
124 /// # use ess::parser::parse;
125 /// let (exprs, err) = parse("1 2 3 ( 4");
126 /// assert_eq!(exprs.len(), 3);
127 /// assert!(err.is_some());
128 /// ```
129 pub fn parse(mut input: &str) -> (Vec<Sexp>, Option<ParseError>) {
130 let mut start_loc = 0;
131 let mut results = Vec::new();
132 loop {
133 match parse_expression(input, start_loc) {
134 Done(rest, result) => {
135 input = rest;
136 start_loc = result.get_loc().1;
137 results.push(result);
138 if rest.trim() == "" {
139 return (results, None);
140 }
141 }
142 Error(err) => {
143 return (results, Some(err));
144 }
145 }
146 }
147 }
148
149 /// Parses a single s-expression, ignoring any trailing text.
150 ///
151 /// This function returns a pair of the parsed s-expression and the tail of the text.
152 ///
153 /// # Errors
154 ///
155 /// If the text begins with an invalid s-expression (imbalanced parenthesis,
156 /// quotes, invalid numbers like 123q, etc.) then the parser will return an
157 /// error. Any text after the first s-expression doesn't affect the parsing.
158 ///
159 /// # Examples
160 ///
161 /// ```rust
162 /// # use ess::parser::parse_one;
163 /// let (expr, rest) = parse_one("1 (").unwrap();
164 /// assert_eq!(rest, " (");
165 /// ```
166 pub fn parse_one(input: &str) -> Result<(Sexp, &str), ParseError> {
167 match parse_expression(input, 0) {
168 Done(rest, result) => Ok((result, rest)),
169 Error(err) => Err(err),
170 }
171 }
172
173 // Core Parsers ////////////////////////////////////////////////////////////////
174
175 // TODO: All of these parsers deserve docs, but since they're somewhat internal
176 // parsers, it's less critical than the rest of the API.
177
178 #[allow(missing_docs)]
179 pub fn parse_expression(input: &str, start_loc: usize) -> ParseResult<Sexp, ParseError> {
180 let (input, start_loc) = consume_whitespace!(input, start_loc, ParseError::Sexp);
181
182 match input.chars().next() {
183 Some('0'...'9') => parse_number(input, start_loc),
184 Some('(') | Some('{') | Some('[') => parse_list(input, start_loc),
185 Some('#') => parse_character(input, start_loc),
186 Some('"') => parse_string(input, start_loc),
187 Some('\'') => match parse_expression(&input[1..], start_loc + 1) {
188 Done(rest, result) => {
189 let span = *result.get_loc();
190 let quote_span = (0, 1).offset(start_loc);
191 Done(
192 rest,
193 Sexp::List(
194 vec![Sexp::Sym("quote".into(), quote_span), result],
195 quote_span.union(&span),
196 ),
197 )
198 }
199 err => err,
200 },
201 Some('`') => match parse_expression(&input[1..], start_loc + 1) {
202 Done(rest, result) => {
203 let span = *result.get_loc();
204 let quote_span = (0, 1).offset(start_loc);
205 Done(
206 rest,
207 Sexp::List(
208 vec![Sexp::Sym("quasiquote".into(), quote_span), result],
209 quote_span.union(&span),
210 ),
211 )
212 }
213 err => err,
214 },
215 Some(',') => {
216 if input[1..].starts_with('@') {
217 match parse_expression(&input[2..], start_loc + 2) {
218 Done(rest, result) => {
219 let span = *result.get_loc();
220 let quote_span = (0, 2).offset(start_loc);
221 Done(
222 rest,
223 Sexp::List(
224 vec![Sexp::Sym("unquote-splicing".into(), quote_span), result],
225 quote_span.union(&span),
226 ),
227 )
228 }
229 err => err,
230 }
231 } else {
232 match parse_expression(&input[1..], start_loc + 1) {
233 Done(rest, result) => {
234 let span = *result.get_loc();
235 let quote_span = (0, 1).offset(start_loc);
236 Done(
237 rest,
238 Sexp::List(
239 vec![Sexp::Sym("unquote".into(), quote_span), result],
240 quote_span.union(&span),
241 ),
242 )
243 }
244 err => err,
245 }
246 }
247 }
248 Some(_) => parse_symbol(input, start_loc),
249 None => unreachable!(),
250 }
251 }
252
253 #[allow(missing_docs)]
254 pub fn parse_list(input: &str, start_loc: usize) -> ParseResult<Sexp, ParseError> {
255 let (input, start_loc) = consume_whitespace!(input, start_loc, ParseError::List);
256
257 let first_char = match input.chars().nth(0) {
258 Some(c @ '(') | Some(c @ '{') | Some(c @ '[') => c,
259 Some(c) => {
260 return Error(ParseError::List(
261 Box::new(ParseError::Unexpected(c, 0)),
262 (0, 0).offset(start_loc),
263 ))
264 }
265 None => unreachable!(),
266 };
267
268 let mut input = &input[1..];
269 let mut loc = start_loc + 1;
270 let mut members = Vec::new();
271 loop {
272 {
273 let (new_input, new_loc) = consume_whitespace!(input, loc, ParseError::List);
274 input = new_input;
275 loc = new_loc;
276 }
277
278 match input.chars().nth(0) {
279 Some(c @ ')') | Some(c @ '}') | Some(c @ ']') => match (first_char, c) {
280 ('(', ')') | ('{', '}') | ('[', ']') => {
281 return Done(&input[1..], Sexp::List(members, (start_loc, loc + 1)))
282 }
283 _ => {
284 return Error(ParseError::List(
285 Box::new(ParseError::Unexpected(c, loc)),
286 (start_loc, loc),
287 ))
288 }
289 },
290 Some(_) => (),
291 None => unreachable!(),
292 }
293
294 match parse_expression(input, loc) {
295 Done(new_input, member) => {
296 loc = member.get_loc().1;
297 members.push(member);
298 input = new_input;
299 }
300 Error(err) => return Error(ParseError::List(Box::new(err), (0, 0).offset(loc))),
301 }
302 }
303 }
304
305 #[allow(missing_docs)]
306 pub fn parse_number(input: &str, start_loc: usize) -> ParseResult<Sexp, ParseError> {
307 let (input, start_loc) = consume_whitespace!(input, start_loc, ParseError::Number);
308
309 match input.chars().next() {
310 Some(c) if !c.is_digit(10) => {
311 return Error(ParseError::Number(
312 Box::new(ParseError::Unexpected(c, start_loc)),
313 (0, c.len_utf8()).offset(start_loc),
314 ));
315 }
316 None => {
317 return Error(ParseError::Number(
318 Box::new(ParseError::UnexpectedEof),
319 (0, 0).offset(start_loc),
320 ))
321 }
322 _ => (),
323 }
324
325 let base = 10;
326
327 let mut end = 0;
328 // Before the decimal point
329 for (i, c) in input.char_indices() {
330 if c == '.' {
331 end = i + 1;
332 break;
333 }
334
335 if c.is_delimiter() {
336 return Done(
337 &input[i..],
338 Sexp::Int(
339 input[..i].parse().expect("Already matched digits"),
340 (0, i).offset(start_loc),
341 ),
342 );
343 }
344
345 if !c.is_digit(base) {
346 return Error(ParseError::Number(
347 Box::new(ParseError::Unexpected(c, start_loc + i)),
348 (i, i).offset(start_loc),
349 ));
350 }
351
352 end = i + c.len_utf8();
353 }
354
355 if input[end..].is_empty() {
356 return Done(
357 &input[end..],
358 Sexp::Int(
359 input.parse().expect("Already matched digits"),
360 (0, end).offset(start_loc),
361 ),
362 );
363 }
364
365 // After the decimal point
366 for (i, c) in input[end..].char_indices() {
367 if c.is_delimiter() {
368 return Done(
369 &input[i + end..],
370 Sexp::Float(
371 input[..end + i]
372 .parse()
373 .expect("Already matched digits.digits"),
374 (0, end + i).offset(start_loc),
375 ),
376 );
377 }
378
379 if !c.is_digit(base) {
380 return Error(ParseError::Number(
381 Box::new(ParseError::Unexpected(c, start_loc + i + end)),
382 (i + end, i + end).offset(start_loc),
383 ));
384 }
385 }
386
387 Done(
388 &input[input.len()..],
389 Sexp::Float(
390 input.parse().expect("Already matched digits.digits"),
391 (0, input.len()).offset(start_loc),
392 ),
393 )
394 }
395
396 #[allow(missing_docs)]
397 pub fn parse_symbol(input: &str, start_loc: usize) -> ParseResult<Sexp, ParseError> {
398 let (input, start_loc) = consume_whitespace!(input, start_loc, ParseError::Symbol);
399
400 match input.chars().next() {
401 Some(c @ '#') | Some(c @ ':') | Some(c @ '0'...'9') => {
402 return Error(ParseError::Symbol(
403 Box::new(ParseError::Unexpected(c, start_loc)),
404 (0, 0).offset(start_loc),
405 ))
406 }
407 Some(c) if c.is_delimiter() => {
408 return Error(ParseError::Symbol(
409 Box::new(ParseError::Unexpected(c, start_loc)),
410 (0, 0).offset(start_loc),
411 ))
412 }
413 Some(_) => (),
414 None => unreachable!(),
415 }
416
417 for (i, c) in input.char_indices() {
418 if c.is_delimiter() {
419 return Done(
420 &input[i..],
421 Sexp::Sym(input[..i].into(), (0, i).offset(start_loc)),
422 );
423 }
424 }
425
426 Done(
427 &input[input.len()..],
428 Sexp::Sym(input.into(), (0, input.len()).offset(start_loc)),
429 )
430 }
431
432 #[allow(missing_docs)]
433 pub fn parse_string(input: &str, start_loc: usize) -> ParseResult<Sexp, ParseError> {
434 let (input, start_loc) = consume_whitespace!(input, start_loc, ParseError::String);
435
436 match input.chars().next() {
437 Some('"') => (),
438 Some(c) => {
439 return Error(ParseError::String(
440 Box::new(ParseError::Unexpected(c, start_loc)),
441 (0, 0).offset(start_loc),
442 ))
443 }
444 None => unreachable!(),
445 }
446
447 for (i, c) in input[1..].char_indices() {
448 if c == '"' {
449 return Done(
450 &input[2 + i..],
451 Sexp::Str(input[1..=i].into(), (0, i + 2).offset(start_loc)),
452 );
453 }
454 }
455
456 Error(ParseError::String(
457 Box::new(ParseError::UnexpectedEof),
458 (0, input.len()).offset(start_loc),
459 ))
460 }
461
462 #[allow(missing_docs)]
463 pub fn parse_character(input: &str, start_loc: usize) -> ParseResult<Sexp, ParseError> {
464 let (input, start_loc) = consume_whitespace!(input, start_loc, ParseError::Char);
465
466 match input.chars().nth(0) {
467 Some('#') => (),
468 Some(c) => {
469 return Error(ParseError::Char(
470 Box::new(ParseError::Unexpected(c, start_loc)),
471 (0, 0).offset(start_loc),
472 ))
473 }
474 None => {
475 return Error(ParseError::Char(
476 Box::new(ParseError::UnexpectedEof),
477 (0, 0).offset(start_loc),
478 ))
479 }
480 }
481
482 match input.chars().nth(1) {
483 Some('\\') => (),
484 Some(c) => {
485 return Error(ParseError::Char(
486 Box::new(ParseError::Unexpected(c, start_loc + 1)),
487 (1, 1).offset(start_loc),
488 ))
489 }
490 None => {
491 return Error(ParseError::Char(
492 Box::new(ParseError::UnexpectedEof),
493 (1, 1).offset(start_loc),
494 ))
495 }
496 }
497
498 match input.chars().nth(2) {
499 Some(c) => Done(&input[3..], Sexp::Char(c, (0, 3).offset(start_loc))),
500 None => Error(ParseError::Char(
501 Box::new(ParseError::UnexpectedEof),
502 (2, 2).offset(start_loc),
503 )),
504 }
505 }
506
507 // Tests ///////////////////////////////////////////////////////////////////////
508
509 #[cfg(test)]
510 mod test {
511 use parser::ParseResult::*;
512 use parser::*;
513 use sexp::Sexp;
514 use span::Span;
515
516 #[test]
517 fn test_parse() {
518 assert_eq!(
519 parse("1 2 3"),
520 (
521 vec![
522 Sexp::Int(1, (0, 1)),
523 Sexp::Int(2, (2, 3)),
524 Sexp::Int(3, (4, 5))
525 ],
526 None
527 )
528 );
529 assert_eq!(
530 parse("1 2 )"),
531 (
532 vec![Sexp::Int(1, (0, 1)), Sexp::Int(2, (2, 3))],
533 Some(ParseError::Symbol(
534 Box::new(ParseError::Unexpected(')', 4)),
535 (4, 4)
536 ))
537 )
538 );
539 }
540
541 #[test]
542 fn test_parse_one() {
543 assert_eq!(parse_one("1 2"), Ok((Sexp::Int(1, (0, 1)), " 2")));
544 }
545
546 #[test]
547 fn test_parse_expression() {
548 assert_eq!(parse_expression(" 1", 0), Done("", Sexp::Int(1, (1, 2))));
549 assert_eq!(
550 parse_expression("2.2", 0),
551 Done("", Sexp::Float(2.2, (0, 3)))
552 );
553 assert_eq!(
554 parse_expression(" a", 0),
555 Done("", Sexp::Sym("a".into(), (1, 2)))
556 );
557 assert_eq!(
558 parse_expression("#\\c", 0),
559 Done("", Sexp::Char('c', (0, 3)))
560 );
561 assert_eq!(
562 parse_expression(r#""hi""#, 0),
563 Done("", Sexp::Str("hi".into(), (0, 4)))
564 );
565 assert_eq!(
566 parse_expression("()", 0),
567 Done("", Sexp::List(vec![], (0, 2)))
568 );
569 assert_eq!(
570 parse_expression("( 1 2 3 )", 0),
571 Done(
572 "",
573 Sexp::List(
574 vec![
575 Sexp::Int(1, (2, 3)),
576 Sexp::Int(2, (4, 5)),
577 Sexp::Int(3, (6, 7)),
578 ],
579 (0, 9)
580 )
581 )
582 );
583
584 assert_eq!(
585 parse_expression("", 0),
586 Error(ParseError::Sexp(
587 Box::new(ParseError::UnexpectedEof),
588 (0, 0)
589 ))
590 );
591 }
592
593 #[test]
594 fn test_parse_expr_quote() {
595 assert_eq!(
596 parse_expression("'a", 0),
597 Done(
598 "",
599 Sexp::List(
600 vec![
601 Sexp::Sym("quote".into(), (0, 1)),
602 Sexp::Sym("a".into(), (1, 2)),
603 ],
604 (0, 2)
605 )
606 )
607 );
608 assert_eq!(
609 parse_expression("'1", 0),
610 Done(
611 "",
612 Sexp::List(
613 vec![Sexp::Sym("quote".into(), (0, 1)), Sexp::Int(1, (1, 2)),],
614 (0, 2)
615 )
616 )
617 );
618 assert_eq!(
619 parse_expression("' (1 2 3)", 0),
620 Done(
621 "",
622 Sexp::List(
623 vec![
624 Sexp::Sym("quote".into(), (0, 1)),
625 Sexp::List(
626 vec![
627 Sexp::Int(1, (3, 4)),
628 Sexp::Int(2, (5, 6)),
629 Sexp::Int(3, (7, 8)),
630 ],
631 (2, 9)
632 ),
633 ],
634 (0, 9)
635 )
636 )
637 );
638
639 assert_eq!(
640 parse_expression("'", 0),
641 Error(ParseError::Sexp(
642 Box::new(ParseError::UnexpectedEof),
643 (1, 1)
644 ))
645 );
646 assert_eq!(
647 parse_expression("`'", 0),
648 Error(ParseError::Sexp(
649 Box::new(ParseError::UnexpectedEof),
650 (2, 2)
651 ))
652 );
653 }
654
655 #[test]
656 fn test_parse_expr_quasiquote() {
657 assert_eq!(
658 parse_expression("`a", 0),
659 Done(
660 "",
661 Sexp::List(
662 vec![
663 Sexp::Sym("quasiquote".into(), (0, 1)),
664 Sexp::Sym("a".into(), (1, 2)),
665 ],
666 (0, 2)
667 )
668 )
669 );
670 assert_eq!(
671 parse_expression("`1", 0),
672 Done(
673 "",
674 Sexp::List(
675 vec![Sexp::Sym("quasiquote".into(), (0, 1)), Sexp::Int(1, (1, 2)),],
676 (0, 2)
677 )
678 )
679 );
680 assert_eq!(
681 parse_expression("` (1 2 3)", 0),
682 Done(
683 "",
684 Sexp::List(
685 vec![
686 Sexp::Sym("quasiquote".into(), (0, 1)),
687 Sexp::List(
688 vec![
689 Sexp::Int(1, (3, 4)),
690 Sexp::Int(2, (5, 6)),
691 Sexp::Int(3, (7, 8)),
692 ],
693 (2, 9)
694 ),
695 ],
696 (0, 9)
697 )
698 )
699 );
700 assert_eq!(
701 parse_expression("`'a", 0),
702 Done(
703 "",
704 Sexp::List(
705 vec![
706 Sexp::Sym("quasiquote".into(), (0, 1)),
707 Sexp::List(
708 vec![
709 Sexp::Sym("quote".into(), (1, 2)),
710 Sexp::Sym("a".into(), (2, 3)),
711 ],
712 (1, 3)
713 ),
714 ],
715 (0, 3)
716 )
717 )
718 );
719
720 assert_eq!(
721 parse_expression("`", 0),
722 Error(ParseError::Sexp(
723 Box::new(ParseError::UnexpectedEof),
724 (1, 1)
725 ))
726 );
727 }
728
729 #[test]
730 fn test_parse_expr_unquote() {
731 assert_eq!(
732 parse_expression(",a", 0),
733 Done(
734 "",
735 Sexp::List(
736 vec![
737 Sexp::Sym("unquote".into(), (0, 1)),
738 Sexp::Sym("a".into(), (1, 2)),
739 ],
740 (0, 2)
741 )
742 )
743 );
744 assert_eq!(
745 parse_expression(",1", 0),
746 Done(
747 "",
748 Sexp::List(
749 vec![Sexp::Sym("unquote".into(), (0, 1)), Sexp::Int(1, (1, 2)),],
750 (0, 2)
751 )
752 )
753 );
754 assert_eq!(
755 parse_expression(", (1 2 3)", 0),
756 Done(
757 "",
758 Sexp::List(
759 vec![
760 Sexp::Sym("unquote".into(), (0, 1)),
761 Sexp::List(
762 vec![
763 Sexp::Int(1, (3, 4)),
764 Sexp::Int(2, (5, 6)),
765 Sexp::Int(3, (7, 8)),
766 ],
767 (2, 9)
768 ),
769 ],
770 (0, 9)
771 )
772 )
773 );
774 assert_eq!(
775 parse_expression("`,a", 0),
776 Done(
777 "",
778 Sexp::List(
779 vec![
780 Sexp::Sym("quasiquote".into(), (0, 1)),
781 Sexp::List(
782 vec![
783 Sexp::Sym("unquote".into(), (1, 2)),
784 Sexp::Sym("a".into(), (2, 3)),
785 ],
786 (1, 3)
787 ),
788 ],
789 (0, 3)
790 )
791 )
792 );
793 assert_eq!(
794 parse_expression("`(,@a)", 0),
795 Done(
796 "",
797 Sexp::List(
798 vec![
799 Sexp::Sym("quasiquote".into(), (0, 1)),
800 Sexp::List(
801 vec![Sexp::List(
802 vec![
803 Sexp::Sym("unquote-splicing".into(), (2, 4)),
804 Sexp::Sym("a".into(), (4, 5)),
805 ],
806 (2, 5)
807 ),],
808 (1, 6)
809 ),
810 ],
811 (0, 6)
812 )
813 )
814 );
815
816 assert_eq!(
817 parse_expression(",", 0),
818 Error(ParseError::Sexp(
819 Box::new(ParseError::UnexpectedEof),
820 (1, 1)
821 ))
822 );
823 assert_eq!(
824 parse_expression(",@", 0),
825 Error(ParseError::Sexp(
826 Box::new(ParseError::UnexpectedEof),
827 (2, 2)
828 ))
829 );
830 }
831
832 #[test]
833 fn test_parse_list() {
834 assert_eq!(parse_list("()", 0), Done("", Sexp::List(vec![], (0, 2))));
835 assert_eq!(
836 parse_list("(1)", 0),
837 Done("", Sexp::List(vec![Sexp::Int(1, (1, 2))], (0, 3)))
838 );
839 assert_eq!(
840 parse_list(" ( 1 2 3 a )", 0),
841 Done(
842 "",
843 Sexp::List(
844 vec![
845 Sexp::Int(1, (4, 5)),
846 Sexp::Int(2, (9, 10)),
847 Sexp::Int(3, (12, 13)),
848 Sexp::Sym("a".into(), (14, 15)),
849 ],
850 (2, 17)
851 )
852 )
853 );
854 }
855
856 #[test]
857 fn test_parse_number() {
858 assert_eq!(parse_number("1", 0), Done("", Sexp::Int(1, (0, 1))));
859 assert_eq!(parse_number(" 13", 0), Done("", Sexp::Int(13, (1, 3))));
860 assert_eq!(parse_number("1.2", 0), Done("", Sexp::Float(1.2, (0, 3))));
861 assert_eq!(
862 parse_number("\u{3000}4.2", 0),
863 Done("", Sexp::Float(4.2, (0, 3).offset('\u{3000}'.len_utf8())))
864 );
865 assert_eq!(parse_number(" 42 ", 0), Done(" ", Sexp::Int(42, (2, 4))));
866 assert_eq!(
867 parse_number(" 4.2 ", 0),
868 Done(" ", Sexp::Float(4.2, (1, 4)))
869 );
870 assert_eq!(parse_number("1()", 0), Done("()", Sexp::Int(1, (0, 1))));
871 assert_eq!(
872 parse_number("3.6()", 0),
873 Done("()", Sexp::Float(3.6, (0, 3)))
874 );
875
876 assert_eq!(
877 parse_number("", 0),
878 Error(ParseError::Number(
879 Box::new(ParseError::UnexpectedEof),
880 (0, 0)
881 ))
882 );
883 assert_eq!(
884 parse_number("123a", 0),
885 Error(ParseError::Number(
886 Box::new(ParseError::Unexpected('a', 3)),
887 (3, 3)
888 ))
889 );
890 assert_eq!(
891 parse_number("66.6+", 0),
892 Error(ParseError::Number(
893 Box::new(ParseError::Unexpected('+', 4)),
894 (4, 4)
895 ))
896 );
897 }
898
899 #[test]
900 fn test_parse_ident() {
901 assert_eq!(
902 parse_symbol("+", 0),
903 Done("", Sexp::Sym("+".into(), (0, 1)))
904 );
905 assert_eq!(
906 parse_symbol(" nil?", 0),
907 Done("", Sexp::Sym("nil?".into(), (1, 5)))
908 );
909 assert_eq!(
910 parse_symbol(" ->socket", 0),
911 Done("", Sexp::Sym("->socket".into(), (1, 9)))
912 );
913 assert_eq!(
914 parse_symbol("fib(", 0),
915 Done("(", Sexp::Sym("fib".into(), (0, 3)))
916 );
917 assert_eq!(
918 parse_symbol("foo2", 0),
919 Done("", Sexp::Sym("foo2".into(), (0, 4)))
920 );
921
922 // We reserve #foo for the implementation to do as it wishes
923 assert_eq!(
924 parse_symbol("#hi", 0),
925 Error(ParseError::Symbol(
926 Box::new(ParseError::Unexpected('#', 0)),
927 (0, 0)
928 ))
929 );
930 // We reserve :foo for keywords
931 assert_eq!(
932 parse_symbol(":hi", 0),
933 Error(ParseError::Symbol(
934 Box::new(ParseError::Unexpected(':', 0)),
935 (0, 0)
936 ))
937 );
938
939 assert_eq!(
940 parse_symbol("", 0),
941 Error(ParseError::Symbol(
942 Box::new(ParseError::UnexpectedEof),
943 (0, 0)
944 ))
945 );
946 assert_eq!(
947 parse_symbol("0", 0),
948 Error(ParseError::Symbol(
949 Box::new(ParseError::Unexpected('0', 0)),
950 (0, 0)
951 ))
952 );
953 assert_eq!(
954 parse_symbol("()", 0),
955 Error(ParseError::Symbol(
956 Box::new(ParseError::Unexpected('(', 0)),
957 (0, 0)
958 ))
959 );
960 }
961
962 #[test]
963 fn test_parse_string() {
964 assert_eq!(
965 parse_string(r#""""#, 0),
966 Done("", Sexp::Str("".into(), (0, 2)))
967 );
968 assert_eq!(
969 parse_string(r#""hello""#, 0),
970 Done("", Sexp::Str("hello".into(), (0, 7)))
971 );
972 assert_eq!(
973 parse_string(
974 r#" "this is a nice string
975 with 0123 things in it""#,
976 0
977 ),
978 Done(
979 "",
980 Sexp::Str(
981 "this is a nice string\nwith 0123 things in it".into(),
982 (2, 48)
983 )
984 )
985 );
986
987 assert_eq!(
988 parse_string("", 0),
989 Error(ParseError::String(
990 Box::new(ParseError::UnexpectedEof),
991 (0, 0)
992 ))
993 );
994 assert_eq!(
995 parse_string(r#""hi"#, 0),
996 Error(ParseError::String(
997 Box::new(ParseError::UnexpectedEof),
998 (0, 3)
999 ))
1000 );
1001 }
1002
1003 #[test]
1004 fn test_parse_char() {
1005 assert_eq!(
1006 parse_character(r#"#\""#, 0),
1007 Done("", Sexp::Char('"', (0, 3)))
1008 );
1009 assert_eq!(
1010 parse_character(r#"#\ "#, 0),
1011 Done("", Sexp::Char(' ', (0, 3)))
1012 );
1013 assert_eq!(
1014 parse_character(r#" #\\"#, 0),
1015 Done("", Sexp::Char('\\', (2, 5)))
1016 );
1017
1018 assert_eq!(
1019 parse_character("", 0),
1020 Error(ParseError::Char(
1021 Box::new(ParseError::UnexpectedEof),
1022 (0, 0)
1023 ))
1024 );
1025 assert_eq!(
1026 parse_character("#", 0),
1027 Error(ParseError::Char(
1028 Box::new(ParseError::UnexpectedEof),
1029 (1, 1)
1030 ))
1031 );
1032 assert_eq!(
1033 parse_character("#\\", 0),
1034 Error(ParseError::Char(
1035 Box::new(ParseError::UnexpectedEof),
1036 (2, 2)
1037 ))
1038 );
1039 assert_eq!(
1040 parse_character("a", 0),
1041 Error(ParseError::Char(
1042 Box::new(ParseError::Unexpected('a', 0)),
1043 (0, 0)
1044 ))
1045 );
1046 }
1047 }