rual-core 0.0.4

A slim, embeddable language
Documentation
use super::*;
use crate::lexing::Lexer;

fn parse(s: &str) -> Result<Expr, String> {
    let lexed = Lexer::from(s).lex_all()?;
    Parser::from(lexed).parse_all()
}

#[test]
fn simple_num_declaration() {
    let expr = parse("let answer = -(+      (   - (-42)))").unwrap();

    assert_eq!(
        Expr::Declaration {
            name: (4, 10),
            val: Box::new(Expr::Value(Value::Num(-42)))
        },
        expr
    );
}

#[test]
fn calc_assignment() {
    let expr = parse("let x = (3 + 13) * 5 / 2").unwrap();

    assert_eq!(
        Expr::Declaration {
            name: (4, 5),
            val: Box::new(Expr::Rpn(vec![
                Expr::Value(Value::Num(3)),
                Expr::Value(Value::Num(13)),
                Expr::Op(Punct::Add),
                Expr::Value(Value::Num(5)),
                Expr::Op(Punct::Mul),
                Expr::Value(Value::Num(2)),
                Expr::Op(Punct::Div),
            ]),)
        },
        expr
    );
}

#[test]
fn simple_string_declaration() {
    let expr = parse("let answer_str = 'forty two'").unwrap();

    assert_eq!(
        Expr::Declaration {
            name: (4, 14),
            val: Box::new(Expr::Value(Value::Str((18, 27))))
        },
        expr
    );
}

#[test]
fn range_declarations() {
    let expr = parse(
        r#"
let xs = [ (5 - 4)..100 ]

let xs = [5..(500000 - 500001 + 1) ]
"#,
    )
    .unwrap();

    assert_eq!(
        Expr::Multiple(vec![
            Expr::Declaration {
                name: (5, 7),
                val: Box::new(Expr::Range {
                    from: Box::new(Expr::Rpn(vec![
                        Expr::Value(Value::Num(5)),
                        Expr::Value(Value::Num(4)),
                        Expr::Op(Punct::Sub)
                    ])),
                    to: Box::new(Expr::Value(Value::Num(100)))
                })
            },
            Expr::Declaration {
                name: (32, 34),
                val: Box::new(Expr::Range {
                    from: Box::new(Expr::Value(Value::Num(5))),
                    to: Box::new(Expr::Rpn(vec![
                        Expr::Value(Value::Num(500000)),
                        Expr::Value(Value::Num(500001)),
                        Expr::Op(Punct::Sub),
                        Expr::Value(Value::Num(1)),
                        Expr::Op(Punct::Add),
                    ]))
                })
            }
        ]),
        expr
    );
}

#[test]
fn a_couple_of_declarations() {
    let expr = parse(
        r#"
let x = (5 - 9)

let y = 'this is y'

-- a comment....

"#,
    )
    .unwrap();

    assert_eq!(
        Expr::Multiple(vec![
            Expr::Declaration {
                name: (5, 6),
                val: Box::new(Expr::Rpn(vec![
                    Expr::Value(Value::Num(5)),
                    Expr::Value(Value::Num(9)),
                    Expr::Op(Punct::Sub)
                ]))
            },
            Expr::Declaration {
                name: (22, 23),
                val: Box::new(Expr::Value(Value::Str((27, 36))))
            }
        ]),
        expr
    );
}

#[test]
fn function_declaration() {
    let expr = parse(
        r#"
function: x, y, z -> {
  let sum = x + y
  sum - z
}
"#,
    )
    .unwrap();

    assert_eq!(
        Expr::FunctionDeclaration {
            name: (1, 9),
            params: vec![(11, 12), (14, 15), (17, 18)],
            body: Box::new(Expr::Multiple(vec![
                Expr::Declaration {
                    name: (30, 33),
                    val: Box::new(Expr::Rpn(vec![
                        Expr::IdentLookup((36, 37)),
                        Expr::IdentLookup((40, 41)),
                        Expr::Op(Punct::Add)
                    ]))
                },
                Expr::Rpn(vec![
                    Expr::IdentLookup((44, 47)),
                    Expr::IdentLookup((50, 51)),
                    Expr::Op(Punct::Sub)
                ])
            ]))
        },
        expr
    )
}

#[test]
fn function_invocation() {
    let expr = parse(
        r#"
function((1 - 3) * 7, 'string', x, g())
"#,
    )
    .unwrap();

    assert_eq!(
        Expr::FunctionCall {
            name: (1, 9),
            args: vec![
                Expr::Rpn(vec![
                    Expr::Value(Value::Num(1)),
                    Expr::Value(Value::Num(3)),
                    Expr::Op(Punct::Sub),
                    Expr::Value(Value::Num(7)),
                    Expr::Op(Punct::Mul)
                ]),
                Expr::Value(Value::Str((24, 30))),
                Expr::IdentLookup((33, 34)),
                Expr::FunctionCall {
                    name: (36, 37),
                    args: vec![]
                }
            ]
        },
        expr
    )
}

#[test]
fn function_invocation_assignment() {
    let expr = parse(
        r#"
let res = sum(9 * 8, (8 -2) * 15, 4 - 1 * 3)
"#,
    )
    .unwrap();

    assert_eq!(
        Expr::Declaration {
            name: (5, 8),
            val: Box::new(Expr::FunctionCall {
                name: (11, 14),
                args: vec![
                    Expr::Rpn(vec![
                        Expr::Value(Value::Num(9)),
                        Expr::Value(Value::Num(8)),
                        Expr::Op(Punct::Mul),
                    ]),
                    Expr::Rpn(vec![
                        Expr::Value(Value::Num(8)),
                        Expr::Value(Value::Num(2)),
                        Expr::Op(Punct::Sub),
                        Expr::Value(Value::Num(15)),
                        Expr::Op(Punct::Mul),
                    ]),
                    Expr::Rpn(vec![
                        Expr::Value(Value::Num(4)),
                        Expr::Value(Value::Num(1)),
                        Expr::Value(Value::Num(3)),
                        Expr::Op(Punct::Mul),
                        Expr::Op(Punct::Sub),
                    ]),
                ]
            })
        },
        expr
    )
}

#[test]
fn parameterless_function_declaration() {
    let expr = parse(
        r#"
function {
  5-8
}
"#,
    )
    .unwrap();

    assert_eq!(
        Expr::FunctionDeclaration {
            name: (1, 9),
            params: vec![],
            body: Box::new(Expr::Rpn(vec![
                Expr::Value(Value::Num(5)),
                Expr::Value(Value::Num(8)),
                Expr::Op(Punct::Sub)
            ]))
        },
        expr
    )
}