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
use crate::{
    Exception, ExceptionValue as EV, Expression, Keyword, Operator, Source, SourcePosition, Symbol,
    Value,
};
use pest::iterators::Pair;
use pest::Parser;

use crate::Locker;

#[derive(Parser)]
#[grammar = "parser/syntax.pest"]
pub struct SyntaxParser;

pub fn parse(code: &str, location: &str) -> Result<Vec<Expression>, Exception> {
    let source = Locker::new(Source::new(String::from(code), String::from(location)));

    match SyntaxParser::parse(Rule::expressions, code) {
        Ok(pairs) => {
            let mut exps = Vec::new();
            for pair in pairs {
                if pair.as_rule() == Rule::EOI {
                    // SOI isn't given
                    continue;
                }
                exps.push(
                    build_expression(pair.clone(), source.clone())?
                        .with_source(SourcePosition::from_pair(&pair, &source)),
                );
            }
            Ok(exps)
        }
        Err(err) => Err(Exception::from(err)),
    }
}

fn build_expression(pair: Pair<'_, Rule>, source: Locker<Source>) -> Result<Expression, Exception> {
    let pos = SourcePosition::new(
        pair.as_span().start_pos().pos(),
        pair.as_span().end_pos().pos(),
        source.clone(),
    );
    match &pair.as_rule() {
        Rule::list => {
            let mut values: Vec<Expression> = Vec::new();
            for elem in pair.into_inner() {
                values.push(
                    build_expression(elem.clone(), source.clone())?
                        .with_source(SourcePosition::from_pair(&elem, &source)),
                )
            }
            Ok(Expression::new(Value::List(values)))
        }
        Rule::symbol => Ok(Expression::new(Value::Symbol(Symbol::new(String::from(
            pair.as_str(),
        ))))
        .with_source(pos)),
        Rule::keyword => Ok(Expression::new(Value::Keyword(Keyword::new(String::from(
            pair.into_inner().next().unwrap().as_str(),
        ))))
        .with_source(pos)),
        Rule::number => match pair.as_str().parse::<f64>() {
            Ok(num) => Ok(Expression::new(Value::Number(num)).with_source(pos)),
            Err(_) => Err(Exception::new(
                EV::Syntax,
                None,
                Some(format!("`{}` is not a valid number", pair.as_str())),
            )),
        },
        Rule::byte => match pair.as_str().replace('b', "").parse::<u8>() {
            Ok(num) => Ok(Expression::new(Value::Byte(num)).with_source(pos)),
            Err(_) => Err(Exception::new(
                EV::Syntax,
                None,
                Some(format!("`{}` is not a valid byte (0-255)", pair.as_str())),
            )),
        },
        Rule::text => Ok(Expression::new(Value::Text(
            pair.into_inner().as_str().to_string(),
        ))),

        // Sugar
        Rule::quote | Rule::eval => {
            let mut elements = vec![Expression::new(Value::Operator(match &pair.as_rule() {
                Rule::quote => Operator::Quote,
                Rule::eval => Operator::Eval,
                _ => unreachable!(),
            }))];
            for elem in pair.into_inner() {
                elements.push(
                    build_expression(elem.clone(), source.clone())?
                        .with_source(SourcePosition::from_pair(&elem, &source)),
                );
            }
            Ok(Expression::new(Value::List(elements)))
        }
        _ => Err(Exception::new(
            EV::Syntax,
            None,
            Some(format!("unknown syntax element `{}`", pair.as_str())),
        )),
    }
}