1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//! Parser of R7RS grammar

#[macro_use]
extern crate pest_derive;

use pest::Parser;
pub use pest::iterators::Pair;

#[cfg(debug_assertions)]
const _GRAMMAR: &str = include_str!("r7rs.pest");

#[derive(Parser)]
#[grammar = "r7rs.pest"]
pub struct R7Parser;

pub fn parse(content: &str) -> Result<Pair<Rule>, String> {
    let parsed = R7Parser::parse(Rule::r7rs, content)
        .map_err(|err| err.to_string())?
        .next();
    if let Some(ast) = parsed {
        Ok(ast)
    } else {
        Err("Empty AST".into())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs;

    fn print_tree(ast: Pair<Rule>, level: u8) {
        let padding = String::from_utf8(vec![b' '; 2 * level as usize]).unwrap();
        eprintln!("{}{:?} : {:?}", padding, ast.as_rule(), ast.as_str());
        for pair in ast.into_inner() {
            print_tree(pair, level + 1);
        }
    }

    #[test]
    fn parse_bool() {
        let parsed = R7Parser::parse(Rule::r7rs, "#t").unwrap().next();
        eprintln!("Start");
        if let Some(pairs) = parsed {
            print_tree(pairs, 0);
        }
        let _ = parse("#t").unwrap();
    }

    #[test]
    fn parse_symbol() {
        let parsed = R7Parser::parse(Rule::r7rs, "'hello").unwrap().next();
        eprintln!("Start");
        if let Some(pairs) = parsed {
            print_tree(pairs, 0);
        }
    }

    #[test]
    fn parse_symbol_2() {
        let parsed = R7Parser::parse(Rule::r7rs, "(quote hello)").unwrap().next();
        eprintln!("Start");
        if let Some(pairs) = parsed {
            print_tree(pairs, 0);
        }
    }

    #[test]
    fn parse_symbol_3() {
        let parsed = R7Parser::parse(Rule::r7rs, "(quote\nhello)")
            .unwrap()
            .next();
        eprintln!("Start");
        if let Some(pairs) = parsed {
            print_tree(pairs, 0);
        }
    }

    #[test]
    fn parse_ambiguous_funcall() {
        let parsed = R7Parser::parse(Rule::r7rs, "(quote\n hello)")
            .unwrap()
            .next();
        eprintln!("Start");
        if let Some(pairs) = parsed {
            print_tree(pairs, 0);
        }
    }

    #[test]
    fn parse_base() {
        let base = fs::read_to_string("../lib/scheme/base.sld").expect("cannot read file");
        let parsed = R7Parser::parse(Rule::r7rs, &base).unwrap().next();
        eprintln!("Start");
        if let Some(pairs) = parsed {
            print_tree(pairs, 0);
        }
    }

    #[test]
    fn parse_comment_only() {
        let parsed = R7Parser::parse(Rule::r7rs, ";;hello");
        assert!(parsed.is_err());
    }

    #[test]
    fn parse_nested_comment() {
        let parsed = R7Parser::parse(Rule::r7rs, "(list #|Not in the list|# stuff)")
            .unwrap()
            .next();
        eprintln!("Start");
        if let Some(pairs) = parsed {
            print_tree(pairs, 0);
        }
    }

    #[test]
    fn parse_bytevector() {
        let parsed = R7Parser::parse(Rule::r7rs, "#u8(12 43 98 01 #xDEADBEEF)")
            .unwrap()
            .next();
        eprintln!("Start");
        if let Some(pairs) = parsed {
            print_tree(pairs, 0);
        }
    }
}