plum

#treesitter#compiler#wasm

git clone https://git.pyrossh.dev/plum

A statically typed, imperative programming language inspired by rust, python


plum-checker/tests/monomorphize_tests.rs
3d6f280 1
#![allow(non_snake_case)]
1b220d2 2
use plum_checker::monomorphize::*;
1b220d2 3
use plum_checker::types::PlumType;
1b220d2 4
use plum_core::ast;
1b220d2 5
1b220d2 6
#[test]
3d6f280 7
fn isGenericParamNameAcceptsSingleUppercaseLettersOnly() {
3d6f280 8
    assert!(isGenericParamName("T"));
3d6f280 9
    assert!(isGenericParamName("W"));
3d6f280 10
    assert!(!isGenericParamName("Int"));
3d6f280 11
    assert!(!isGenericParamName("TU"));
3d6f280 12
    assert!(!isGenericParamName("a"));
3d6f280 13
    assert!(!isGenericParamName(""));
1b220d2 14
}
1b220d2 15
1b220d2 16
#[test]
3d6f280 17
fn classGenericParamsReadsDeclaredGenericsList() {
1b220d2 18
    let c = ast::Class {
1b220d2 19
        name: "Box".to_string(),
1b220d2 20
        implements: vec![],
30ae945 21
        generics: vec![ast::GenericParam { name: "T".to_string(), bounds: vec![] }],
30ae945 22
        fields: vec![ast::Field { name: "value".to_string(), ty: ast::Type { name: "T".to_string(), generics: vec![] } }],
1b220d2 23
    };
3d6f280 24
    assert_eq!(classGenericParams(&c), vec!["T".to_string()]);
1b220d2 25
}
1b220d2 26
1b220d2 27
#[test]
3d6f280 28
fn fnGenericParamsDetectsImplicitUppercaseLetterTypesInOrder() {
1b220d2 29
    let f = ast::Fn {
0000000 30
        is_extern: false,
1b220d2 31
        name: "pair".to_string(),
1b220d2 32
        type_param: None,
1b220d2 33
        params: vec![
30ae945 34
            ast::Param { name: "first".to_string(), ty: ast::ParamType::Type(ast::Type { name: "T".to_string(), generics: vec![] }), default: None },
30ae945 35
            ast::Param { name: "second".to_string(), ty: ast::ParamType::Type(ast::Type { name: "U".to_string(), generics: vec![] }), default: None },
1b220d2 36
        ],
30ae945 37
        returns: Some(ast::Type { name: "Bool".to_string(), generics: vec![] }),
1b220d2 38
        body: ast::FnBody::Block(ast::Block { stmts: vec![] }),
1b220d2 39
    };
3d6f280 40
    assert_eq!(fnGenericParams(&f), vec!["T".to_string(), "U".to_string()]);
1b220d2 41
}
1b220d2 42
1b220d2 43
#[test]
3d6f280 44
fn enumGenericParamsDetectsImplicitUppercaseLetterVariantFields() {
1b220d2 45
    let e = ast::Enum {
1b220d2 46
        name: "Option".to_string(),
4fda634 47
        params: vec![],
1b220d2 48
        variants: vec![
4fda634 49
            ast::EnumVariant { name: "Some".to_string(), fields: vec!["T".to_string()], values: vec![] },
4fda634 50
            ast::EnumVariant { name: "None".to_string(), fields: vec![], values: vec![] },
1b220d2 51
        ],
1b220d2 52
    };
3d6f280 53
    assert_eq!(enumGenericParams(&e), vec!["T".to_string()]);
1b220d2 54
}
1b220d2 55
1b220d2 56
#[test]
3d6f280 57
fn mangleJoinsBaseNameAndTypeArgs() {
1b220d2 58
    assert_eq!(mangle("Box", &[PlumType::TInt]), "Box$Int");
1b220d2 59
    assert_eq!(mangle("Pair", &[PlumType::TInt, PlumType::TStr]), "Pair$Int$Str");
1b220d2 60
    assert_eq!(mangle("Green", &[]), "Green");
1b220d2 61
}
1b220d2 62
1b220d2 63
#[test]
3d6f280 64
fn specializeClassSubstitutesGenericFieldTypesAndClearsGenericsList() {
1b220d2 65
    let c = ast::Class {
1b220d2 66
        name: "Box".to_string(),
1b220d2 67
        implements: vec![],
30ae945 68
        generics: vec![ast::GenericParam { name: "T".to_string(), bounds: vec![] }],
30ae945 69
        fields: vec![ast::Field { name: "value".to_string(), ty: ast::Type { name: "T".to_string(), generics: vec![] } }],
1b220d2 70
    };
1b220d2 71
    let mut bindings = std::collections::BTreeMap::new();
30ae945 72
    bindings.insert("T".to_string(), PlumType::TInt);
3d6f280 73
    let specialized = specializeClass(&c, &Substitution(bindings), "Box$Int");
1b220d2 74
    assert_eq!(specialized.name, "Box$Int");
1b220d2 75
    assert!(specialized.generics.is_empty());
1b220d2 76
    assert_eq!(specialized.fields[0].ty.name, "Int");
1b220d2 77
}
1b220d2 78
1b220d2 79
#[test]
3d6f280 80
fn specializeFnSubstitutesGenericParamAndReturnTypes() {
1b220d2 81
    let f = ast::Fn {
0000000 82
        is_extern: false,
1b220d2 83
        name: "wrap".to_string(),
1b220d2 84
        type_param: None,
30ae945 85
        params: vec![ast::Param { name: "value".to_string(), ty: ast::ParamType::Type(ast::Type { name: "T".to_string(), generics: vec![] }), default: None }],
30ae945 86
        returns: Some(ast::Type { name: "T".to_string(), generics: vec![] }),
1b220d2 87
        body: ast::FnBody::Expr(ast::Expr::Var("value".to_string())),
1b220d2 88
    };
1b220d2 89
    let mut bindings = std::collections::BTreeMap::new();
30ae945 90
    bindings.insert("T".to_string(), PlumType::TInt);
3d6f280 91
    let specialized = specializeFn(&f, &Substitution(bindings), "wrap$Int", None);
1b220d2 92
    assert_eq!(specialized.name, "wrap$Int");
1b220d2 93
    match &specialized.params[0].ty {
1b220d2 94
        ast::ParamType::Type(t) => assert_eq!(t.name, "Int"),
1b220d2 95
        _ => panic!("expected ParamType::Type"),
1b220d2 96
    }
1b220d2 97
    assert_eq!(specialized.returns.unwrap().name, "Int");
1b220d2 98
}
1b220d2 99
1b220d2 100
#[test]
3d6f280 101
fn specializeFnSetsNewReceiverForAMethod() {
1b220d2 102
    let f = ast::Fn {
0000000 103
        is_extern: false,
1b220d2 104
        name: "getValue".to_string(),
1b220d2 105
        type_param: Some("Box".to_string()),
1b220d2 106
        params: vec![],
30ae945 107
        returns: Some(ast::Type { name: "T".to_string(), generics: vec![] }),
1b220d2 108
        body: ast::FnBody::Expr(ast::Expr::Self_),
1b220d2 109
    };
1b220d2 110
    let mut bindings = std::collections::BTreeMap::new();
30ae945 111
    bindings.insert("T".to_string(), PlumType::TStr);
3d6f280 112
    let specialized = specializeFn(&f, &Substitution(bindings), "getValue", Some("Box$Str".to_string()));
1b220d2 113
    assert_eq!(specialized.name, "getValue");
1b220d2 114
    assert_eq!(specialized.type_param, Some("Box$Str".to_string()));
1b220d2 115
    assert_eq!(specialized.returns.unwrap().name, "Str");
1b220d2 116
}
1b220d2 117
1b220d2 118
#[test]
3d6f280 119
fn specializeEnumSubstitutesGenericVariantFieldNames() {
1b220d2 120
    let e = ast::Enum {
1b220d2 121
        name: "Option".to_string(),
4fda634 122
        params: vec![],
1b220d2 123
        variants: vec![
4fda634 124
            ast::EnumVariant { name: "Some".to_string(), fields: vec!["T".to_string()], values: vec![] },
4fda634 125
            ast::EnumVariant { name: "None".to_string(), fields: vec![], values: vec![] },
1b220d2 126
        ],
1b220d2 127
    };
1b220d2 128
    let mut bindings = std::collections::BTreeMap::new();
30ae945 129
    bindings.insert("T".to_string(), PlumType::TInt);
3d6f280 130
    let specialized = specializeEnum(&e, &Substitution(bindings), "Option$Int");
1b220d2 131
    assert_eq!(specialized.name, "Option$Int");
1b220d2 132
    assert_eq!(specialized.variants[0].fields, vec!["Int".to_string()]);
1b220d2 133
    assert!(specialized.variants[1].fields.is_empty());
1b220d2 134
}