ayaka-script 0.3.0

First-class script language in Ayaka.
Documentation
use crate::*;
use lalrpop_util::lalrpop_mod;

lalrpop_mod!(
    #[allow(missing_docs)]
    #[allow(dead_code)]
    #[allow(clippy::all)]
    #[allow(unused_imports)]
    grammer
);

pub use grammer::{ConstParser, ExprParser, ProgramParser, RefParser};

impl std::str::FromStr for Program {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        ProgramParser::new()
            .parse(s)
            .map_err(|e| anyhow::anyhow!("{}", e))
    }
}

#[cfg(test)]
mod test {
    use crate::*;

    fn var(s: &str) -> Expr {
        Expr::Ref(Ref::Var(s.into()))
    }

    #[test]
    fn program() {
        assert_eq!(
            ProgramParser::new()
                .parse(
                    "foo(a);
                    foo.bar(a, b)"
                )
                .unwrap(),
            Program(vec![
                Expr::Call(String::default(), "foo".into(), vec![var("a")]),
                Expr::Call("foo".into(), "bar".into(), vec![var("a"), var("b")])
            ])
        );
    }

    #[test]
    fn expr() {
        assert_eq!(ExprParser::new().parse("a").unwrap(), var("a"));
        assert_eq!(
            ExprParser::new().parse("!(a && b || c)").unwrap(),
            Expr::Unary(
                UnaryOp::Not,
                Box::new(Expr::Binary(
                    Box::new(Expr::Binary(
                        Box::new(var("a")),
                        BinaryOp::Logic(LogicBinaryOp::And),
                        Box::new(var("b"))
                    )),
                    BinaryOp::Logic(LogicBinaryOp::Or),
                    Box::new(var("c"))
                ))
            )
        );
        assert_eq!(
            ExprParser::new().parse("foo(a)").unwrap(),
            Expr::Call(String::default(), "foo".into(), vec![var("a")])
        );
        assert_eq!(
            ExprParser::new().parse("foo.bar(a, b)").unwrap(),
            Expr::Call("foo".into(), "bar".into(), vec![var("a"), var("b")])
        );
        assert_eq!(
            ExprParser::new().parse("a + (b * (c & d))").unwrap(),
            Expr::Binary(
                Box::new(var("a")),
                BinaryOp::Val(ValBinaryOp::Add),
                Box::new(Expr::Binary(
                    Box::new(var("b")),
                    BinaryOp::Val(ValBinaryOp::Mul),
                    Box::new(Expr::Binary(
                        Box::new(var("c")),
                        BinaryOp::Val(ValBinaryOp::And),
                        Box::new(var("d"))
                    ))
                ))
            )
        );
    }

    #[test]
    fn r#const() {
        assert_eq!(ConstParser::new().parse("~").unwrap(), RawValue::Unit);

        assert_eq!(
            ConstParser::new().parse("true").unwrap(),
            RawValue::Bool(true)
        );
        assert_eq!(
            ConstParser::new().parse("false").unwrap(),
            RawValue::Bool(false)
        );

        assert_eq!(
            ConstParser::new().parse("114514").unwrap(),
            RawValue::Num(114514.into())
        );

        assert_eq!(
            ConstParser::new().parse("\"Hello world!\"").unwrap(),
            RawValue::Str("Hello world!".into())
        );
    }

    #[test]
    fn r#ref() {
        assert_eq!(RefParser::new().parse("a").unwrap(), Ref::Var("a".into()));
        assert_eq!(RefParser::new().parse("$a").unwrap(), Ref::Ctx("a".into()));
    }
}