luau-syntax 0.732.0

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

// Parser.test.cpp: type_alias_to_a_typeof
#[test]
fn type_alias_to_a_typeof() {
    with_parse(
        r#"
        type A = typeof(1)
    "#,
        ParseOptions::default(),
        |result| {
            let result = result.unwrap();

            let [statement] = statement_kinds(result.root.as_slice()).exact();
            let type_alias = statement.as_type_alias().expect("expected type alias");
            assert_eq!(type_alias.location(), loc!(pos!(1, 8), pos!(1, 26)));
        },
    );
}
// Parser.test.cpp: type_alias_should_point_to_string
#[test]
fn type_alias_should_point_to_string() {
    with_parse(
        r#"
        type A = string
    "#,
        ParseOptions::default(),
        |result| {
            let result = result.unwrap();

            let [statement] = statement_kinds(result.root.as_slice()).exact();
            assert_eq!(statement.tag, StatementTag::TypeAlias);
        },
    );
}
// Parser.test.cpp: type_alias_should_not_interfere_with_type_function_call_or_assignment
#[test]
fn type_alias_should_not_interfere_with_type_function_call_or_assignment() {
    with_parse(
        r#"
        type("a")
        type = nil
    "#,
        ParseOptions::default(),
        |result| {
            let result = result.unwrap();

            let [first, second] = statement_kinds(result.root.as_slice()).exact();
            assert!(matches!(
                first.as_expression().map(|statement| statement.expr.kind()),
                Some(ExpressionKind::Call { .. })
            ));
            assert_eq!(second.tag, StatementTag::Assign);
        },
    );
}
// Parser.test.cpp: type_alias_should_work_when_name_is_also_local
#[test]
fn type_alias_should_work_when_name_is_also_local() {
    with_parse(
        r#"
        local A = nil
        type A = string
    "#,
        ParseOptions::default(),
        |result| {
            let result = result.unwrap();

            let [first, second] = statement_kinds(result.root.as_slice()).exact();
            assert_eq!(first.tag, StatementTag::Local);
            assert_eq!(second.tag, StatementTag::TypeAlias);
        },
    );
}
// Parser.test.cpp: type_alias_span_is_correct
#[test]
fn type_alias_span_is_correct() {
    with_parse(
        r#"
        type Packed1<T...> = (T...) -> (T...)
        type Packed2<T...> = (Packed1<T...>, T...) -> (Packed1<T...>, T...)
    "#,
        ParseOptions::default().with_cst_data(true),
        |result| {
            let result = result.unwrap();

            let [first, second] = statement_kinds(result.root.as_slice()).exact();
            let first = first.as_type_alias().expect("expected packed type alias");
            let second = second.as_type_alias().expect("expected packed type alias");
            assert_eq!(first.location(), loc!(pos!(1, 8), pos!(1, 45)));
            assert_eq!(second.location(), loc!(pos!(2, 8), pos!(2, 75)));
        },
    );
}

// Parser.test.cpp: prefixed_type_reference_links_to_local
#[test]
fn prefixed_type_reference_links_to_local() {
    let _prefix_local = flags::LuauTrackPrefixLocal.scoped(true);
    with_parse_ok(
        r#"
        local Types = nil
        type Foo = Types.Bar
    "#,
        |result| {
            let [local, alias] = statement_kinds(result.root.as_slice()).exact();
            let local = local.as_local().expect("expected local statement").bindings[0];
            let alias = alias.as_type_alias().expect("expected type alias");
            let TypeKind::Reference {
                prefix,
                prefix_local,
                name,
                ..
            } = alias.ty.kind()
            else {
                panic!("expected type reference");
            };
            assert_eq!(prefix.expect("expected prefix"), "Types");
            assert_eq!(name, "Bar");
            assert!(prefix_local.is_some_and(|prefix| std::ptr::eq(prefix, local)));
        },
    );
}

// Parser.test.cpp: unknown_prefixed_type_reference_has_no_local
#[test]
fn unknown_prefixed_type_reference_has_no_local() {
    let _prefix_local = flags::LuauTrackPrefixLocal.scoped(true);
    with_parse_ok("type Foo = Unknown.Bar", |result| {
        let [alias] = statement_kinds(result.root.as_slice()).exact();
        let alias = alias.as_type_alias().expect("expected type alias");
        let TypeKind::Reference {
            prefix,
            prefix_local,
            ..
        } = alias.ty.kind()
        else {
            panic!("expected type reference");
        };
        assert_eq!(prefix.expect("expected prefix"), "Unknown");
        assert!(prefix_local.is_none());
    });
}

// Parser.test.cpp: prefixed_type_reference_shadowing
#[test]
fn prefixed_type_reference_shadowing() {
    let _prefix_local = flags::LuauTrackPrefixLocal.scoped(true);
    with_parse_ok(
        r#"
        local Types = nil
        do
            local Types = nil
            type Foo = Types.Bar
        end
        type Bar = Types.Baz
    "#,
        |result| {
            let [outer_local, inner_block, outer_alias] =
                statement_kinds(result.root.as_slice()).exact();
            let outer_local = outer_local
                .as_local()
                .expect("expected outer local")
                .bindings[0];
            let [inner_local, inner_alias] = statement_kinds(
                inner_block
                    .as_block()
                    .expect("expected do block")
                    .as_slice(),
            )
            .exact();
            let inner_local = inner_local
                .as_local()
                .expect("expected inner local")
                .bindings[0];

            let inner_alias = inner_alias.as_type_alias().expect("expected inner alias");
            let TypeKind::Reference {
                prefix_local: Some(inner_prefix),
                ..
            } = inner_alias.ty.kind()
            else {
                panic!("expected linked inner type reference");
            };
            assert!(std::ptr::eq(inner_prefix, inner_local));

            let outer_alias = outer_alias.as_type_alias().expect("expected outer alias");
            let TypeKind::Reference {
                prefix_local: Some(outer_prefix),
                ..
            } = outer_alias.ty.kind()
            else {
                panic!("expected linked outer type reference");
            };
            assert!(std::ptr::eq(outer_prefix, outer_local));
            assert!(!std::ptr::eq(inner_prefix, outer_prefix));
        },
    );
}
// Parser.test.cpp: parse_export_type
#[test]
fn parse_export_type() {
    with_parse(
        r#"
        export()
        export = 5
        export, export = export
        export type A = number
        type A = number
    "#,
        ParseOptions::default(),
        |result| {
            let result = result.unwrap();

            let statements = statement_kinds(result.root.as_slice()).exact::<5>();
            assert_eq!(statements[0].tag, StatementTag::Expression);
            assert_eq!(statements[1].tag, StatementTag::Assign);
            assert_eq!(statements[2].tag, StatementTag::Assign);
            assert_eq!(statements[3].tag, StatementTag::TypeAlias);
            assert_eq!(statements[4].tag, StatementTag::TypeAlias);
        },
    );
}