luau-syntax 0.732.0

Luau lexer, parser, AST, CST, and source utilities
Documentation
use super::super::common::*;
use luau_common::flags;

fn with_return_expressions<R>(
    source: &str,
    options: ParseOptions,
    f: impl for<'ast> FnOnce(&'ast [Expression<'ast>]) -> R,
) -> R {
    with_parse(source, options, |result| {
        let result = result.unwrap();
        let [statement] = statement_kinds(result.root.as_slice()).exact();
        let return_statement = statement.as_return().expect("expected return statement");
        f(return_statement.expressions)
    })
}

fn number_values(expressions: &[Expression]) -> Vec<f64> {
    expressions
        .iter()
        .map(|expression| match expression.kind() {
            ExpressionKind::Number { value, .. } => value,
            _ => panic!("expected number expression"),
        })
        .collect()
}

fn integer_values(expressions: &[Expression]) -> Vec<i64> {
    expressions
        .iter()
        .map(|expression| match expression.kind() {
            ExpressionKind::Integer { value, .. } => value,
            _ => panic!("expected integer expression"),
        })
        .collect()
}

// Parser.test.cpp: number_literals
#[test]
fn number_literals() {
    assert_eq!(
        with_return_expressions(
            r#"
return
1,
1.5,
.5,
12_34_56,
0x1234,
 0b010101
"#,
            ParseOptions::default(),
            number_values
        ),
        [1.0, 1.5, 0.5, 123456.0, 0x1234 as f64, 0x15 as f64]
    );
}

// Parser.test.cpp: parse_numbers_decimal
#[test]
fn parse_numbers_decimal() {
    assert_eq!(
        with_return_expressions(
            "return 1, .5, 1.5, 1e-5, 1.5e-5, 12_345.1_25",
            ParseOptions::default(),
            number_values
        ),
        [1.0, 0.5, 1.5, 1.0e-5, 1.5e-5, 12345.125]
    );

    let _integer = flags::LuauIntegerType2.scoped(true);
    assert_eq!(
        with_return_expressions(
            "return 1i, 1_000_000i",
            ParseOptions::default(),
            integer_values
        ),
        [1, 1_000_000]
    );
}

// Parser.test.cpp: parse_numbers_hexadecimal
#[test]
fn parse_numbers_hexadecimal() {
    assert_eq!(
        with_return_expressions(
            "return 0xab, 0xAB05, 0xff_ff, 0xffffffffffffffff",
            ParseOptions::default(),
            number_values
        ),
        [0xab as f64, 0xAB05 as f64, 0xFFFF as f64, u64::MAX as f64]
    );

    let _integer = flags::LuauIntegerType2.scoped(true);
    assert_eq!(
        with_return_expressions(
            "return 0xabi, 0XAB05i, 0xff_ffi, 0x7fffffffffffffffi, 0x8000000000000000i, 0xffffffffffffffffi",
            ParseOptions::default(),
            integer_values
        ),
        [0xab, 0xAB05, 0xFFFF, i64::MAX, i64::MIN, -1]
    );
}

// Parser.test.cpp: parse_numbers_binary
#[test]
fn parse_numbers_binary() {
    assert_eq!(
        with_return_expressions(
            "return 0b1, 0b0, 0b101010, 0b1111111111111111111111111111111111111111111111111111111111111111",
            ParseOptions::default(),
            number_values
        ),
        [1.0, 0.0, 42.0, u64::MAX as f64]
    );

    let _integer = flags::LuauIntegerType2.scoped(true);
    assert_eq!(
        with_return_expressions(
            concat!(
                "return 0b1i, 0b0i, 0b101010i, ",
                "0b111111111111111111111111111111111111111111111111111111111111111i, ",
                "0b1000000000000000000000000000000000000000000000000000000000000000i, ",
                "0b1111111111111111111111111111111111111111111111111111111111111111i",
            ),
            ParseOptions::default(),
            integer_values
        ),
        [1, 0, 42, i64::MAX, i64::MIN, -1]
    );
}

// Parser.test.cpp: parse_numbers_error
#[test]
fn parse_numbers_error() {
    for (source, expected) in [
        ("return 0b123", "Malformed number"),
        ("return 0b0b1", "Malformed number"),
        ("return 123x", "Malformed number"),
        ("return 0xg", "Malformed number"),
        ("return 0x0x123", "Malformed number"),
        ("return 0xffffffffffffffffffffllllllg", "Malformed number"),
        (
            "return 0x0xffffffffffffffffffffffffffff",
            "Malformed number",
        ),
    ] {
        parse_errors(source).assert_first_message(expected);
    }

    let _integer = flags::LuauIntegerType2.scoped(true);
    for (source, expected) in [
        ("return 0x0xABCi", "Malformed integer"),
        ("return 0xABCMi", "Malformed integer"),
        ("return 0b250i", "Malformed integer"),
        ("return 0bbbbi", "Malformed integer"),
        ("return 0b0b1i", "Malformed integer"),
        ("return 123ii", "Malformed integer"),
        ("return 0xABii", "Malformed integer"),
        ("return 99999999999999999999i", "Integer overflow"),
        ("return 0xFFFFFFFFFFFFFFFFFFi", "Integer overflow"),
        (
            "return 0b10000000000000000000000000000000000000000000000000000000000000000i",
            "Integer overflow",
        ),
        ("return 123ii", "Malformed integer"),
        ("return 0xABii", "Malformed integer"),
    ] {
        parse_errors_with_options(source, ParseOptions::default()).assert_first_message(expected);
    }
}