arithmetic-parser 0.3.0

Parser for arithmetic expressions with flexible literals and type annotations.
Documentation
//! Tests for tuples and destructuring.

use super::{lsp, lvalue_tuple, sp, span, FieldGrammar, Literal, ValueType};
use crate::{
    parser::{destructure, expr, lvalue, paren_expr, Complete},
    BinaryOp, Destructure, DestructureRest, Expr, InputSpan, Lvalue, Spanned,
};

#[test]
fn tuples_are_parsed() {
    let input = InputSpan::new("(x, y)");
    assert_eq!(
        paren_expr::<FieldGrammar, Complete>(input).unwrap().1.extra,
        Expr::Tuple(vec![sp(1, "x", Expr::Variable), sp(4, "y", Expr::Variable)])
    );

    let input = InputSpan::new("(x / 2, G^y, 1)");
    assert_eq!(
        paren_expr::<FieldGrammar, Complete>(input).unwrap().1.extra,
        Expr::Tuple(vec![
            sp(
                1,
                "x / 2",
                Expr::Binary {
                    lhs: Box::new(sp(1, "x", Expr::Variable)),
                    op: BinaryOp::from_span(span(3, "/")),
                    rhs: Box::new(sp(5, "2", Expr::Literal(Literal::Number))),
                }
            ),
            sp(
                8,
                "G^y",
                Expr::Binary {
                    lhs: Box::new(sp(8, "G", Expr::Variable)),
                    op: BinaryOp::from_span(span(9, "^")),
                    rhs: Box::new(sp(10, "y", Expr::Variable)),
                }
            ),
            sp(13, "1", Expr::Literal(Literal::Number)),
        ]),
    );
}

#[test]
fn empty_tuple_is_parsed() {
    let input = InputSpan::new("();");
    let value = expr::<FieldGrammar, Complete>(input).unwrap().1;
    assert_eq!(value, sp(0, "()", Expr::Tuple(vec![])));
}

#[test]
fn single_value_tuple_is_parsed() {
    let input = InputSpan::new("(1,);");
    let value = expr::<FieldGrammar, Complete>(input).unwrap().1;
    assert_eq!(
        value,
        sp(
            0,
            "(1,)",
            Expr::Tuple(vec![sp(1, "1", Expr::Literal(Literal::Number))])
        )
    );
}

#[test]
fn destructuring_is_parsed() {
    let input = InputSpan::new("x, y)");
    let expected = Destructure {
        start: vec![
            lsp(0, "x", Lvalue::Variable { ty: None }),
            lsp(3, "y", Lvalue::Variable { ty: None }),
        ],
        middle: None,
        end: vec![],
    };
    assert_eq!(
        destructure::<FieldGrammar, Complete>(input).unwrap().1,
        expected
    );

    let input = InputSpan::new("x, y ,\n)");
    let (rest, parsed) = destructure::<FieldGrammar, Complete>(input).unwrap();
    assert_eq!(parsed, expected);
    assert_eq!(*rest.fragment(), ")");

    let input = InputSpan::new("x, ..., y)");
    assert_eq!(
        destructure::<FieldGrammar, Complete>(input).unwrap().1,
        Destructure {
            start: vec![lsp(0, "x", Lvalue::Variable { ty: None })],
            middle: Some(Spanned::new(span(3, "..."), DestructureRest::Unnamed)),
            end: vec![lsp(8, "y", Lvalue::Variable { ty: None })],
        }
    );

    let input = InputSpan::new("x, ...rest, y: Ge, z)");
    assert_eq!(
        destructure::<FieldGrammar, Complete>(input).unwrap().1,
        Destructure {
            start: vec![lsp(0, "x", Lvalue::Variable { ty: None })],
            middle: Some(Spanned::new(
                span(3, "...rest"),
                DestructureRest::Named {
                    variable: span(6, "rest").into(),
                    ty: None,
                }
            )),
            end: vec![
                lsp(
                    12,
                    "y",
                    Lvalue::Variable {
                        ty: Some(Spanned::new(span(15, "Ge"), ValueType::Element))
                    }
                ),
                lsp(19, "z", Lvalue::Variable { ty: None })
            ],
        }
    );

    let input = InputSpan::new("...xs: Ge, end)");
    assert_eq!(
        destructure::<FieldGrammar, Complete>(input).unwrap().1,
        Destructure {
            start: vec![],
            middle: Some(Spanned::new(
                span(0, "...xs: Ge"),
                DestructureRest::Named {
                    variable: span(3, "xs").into(),
                    ty: Some(Spanned::new(span(7, "Ge"), ValueType::Element))
                }
            )),
            end: vec![lsp(11, "end", Lvalue::Variable { ty: None })],
        }
    );
}

#[test]
fn nested_destructuring_is_parsed() {
    let input = InputSpan::new("(x, y), ..., (_, ...rest),\n|");
    let start = Destructure {
        start: vec![
            lsp(1, "x", Lvalue::Variable { ty: None }),
            lsp(4, "y", Lvalue::Variable { ty: None }),
        ],
        middle: None,
        end: vec![],
    };
    let end = Destructure {
        start: vec![lsp(14, "_", Lvalue::Variable { ty: None })],
        middle: Some(Spanned::new(
            span(17, "...rest"),
            DestructureRest::Named {
                variable: span(20, "rest").into(),
                ty: None,
            },
        )),
        end: vec![],
    };

    assert_eq!(
        destructure::<FieldGrammar, Complete>(input).unwrap().1,
        Destructure {
            start: vec![Spanned::new(span(0, "(x, y)"), Lvalue::Tuple(start))],
            middle: Some(Spanned::new(span(8, "..."), DestructureRest::Unnamed)),
            end: vec![Spanned::new(span(13, "(_, ...rest)"), Lvalue::Tuple(end))],
        }
    );
}

#[test]
fn lvalues_are_parsed() {
    let input = InputSpan::new("x =");
    assert_eq!(
        lvalue::<FieldGrammar, Complete>(input).unwrap().1.extra,
        Lvalue::Variable { ty: None }
    );

    let input = InputSpan::new("(x, (y, z)) =");
    assert_eq!(
        lvalue::<FieldGrammar, Complete>(input).unwrap().1.extra,
        lvalue_tuple(vec![
            lsp(1, "x", Lvalue::Variable { ty: None }),
            lsp(
                4,
                "(y, z)",
                lvalue_tuple(vec![
                    lsp(5, "y", Lvalue::Variable { ty: None }),
                    lsp(8, "z", Lvalue::Variable { ty: None }),
                ])
            )
        ])
    );

    let input = InputSpan::new("(x: (Sc, _), (y, z: Ge)) =");
    assert_eq!(
        lvalue::<FieldGrammar, Complete>(input).unwrap().1.extra,
        lvalue_tuple(vec![
            lsp(
                1,
                "x",
                Lvalue::Variable {
                    ty: Some(Spanned::new(
                        span(4, "(Sc, _)"),
                        ValueType::Tuple(vec![ValueType::Scalar, ValueType::Any])
                    )),
                }
            ),
            lsp(
                13,
                "(y, z: Ge)",
                lvalue_tuple(vec![
                    lsp(14, "y", Lvalue::Variable { ty: None }),
                    lsp(
                        17,
                        "z",
                        Lvalue::Variable {
                            ty: Some(Spanned::new(span(20, "Ge"), ValueType::Element)),
                        }
                    ),
                ])
            )
        ])
    );
}