1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
use std::mem;

use erg_common::Str;

use erg_type::constructors::{and, mono};
use erg_type::value::{TypeKind, TypeObj, ValueObj};
use erg_type::Type;
use erg_type::ValueArgs;

fn value_obj_to_t(value: ValueObj) -> TypeObj {
    match value {
        ValueObj::Type(t) => t,
        ValueObj::Record(rec) => TypeObj::Builtin(Type::Record(
            rec.into_iter()
                .map(|(k, v)| (k, value_obj_to_t(v).typ().clone()))
                .collect(),
        )),
        other => todo!("{other}"),
    }
}

/// Requirement: Type, Impl := Type -> ClassType
pub fn class_func(mut args: ValueArgs, __name__: Option<Str>) -> ValueObj {
    let require = args.remove_left_or_key("Requirement").unwrap();
    let require = value_obj_to_t(require);
    let impls = args.remove_left_or_key("Impl");
    let impls = impls.map(value_obj_to_t);
    let t = mono(__name__.unwrap_or(Str::ever("<Lambda>")));
    ValueObj::gen_t(TypeKind::Class, t, require, impls, None)
}

/// Super: Type, Impl := Type, Additional := Type -> ClassType
pub fn inherit_func(mut args: ValueArgs, __name__: Option<Str>) -> ValueObj {
    let sup = args.remove_left_or_key("Super").unwrap();
    let sup = value_obj_to_t(sup);
    let impls = args.remove_left_or_key("Impl");
    let impls = impls.map(value_obj_to_t);
    let additional = args.remove_left_or_key("Additional");
    let additional = additional.map(value_obj_to_t);
    let t = mono(__name__.unwrap_or(Str::ever("<Lambda>")));
    ValueObj::gen_t(TypeKind::Subclass, t, sup, impls, additional)
}

/// Class: ClassType -> ClassType (with `InheritableType`)
/// This function is used by the compiler to mark a class as inheritable and does nothing in terms of actual operation.
pub fn inheritable_func(mut args: ValueArgs, __name__: Option<Str>) -> ValueObj {
    let class = args.remove_left_or_key("Class").unwrap();
    match class {
        ValueObj::Type(TypeObj::Generated(mut gen)) => {
            if let Some(typ) = &mut gen.impls {
                match typ.as_mut() {
                    TypeObj::Generated(gen) => {
                        gen.t = and(mem::take(&mut gen.t), mono("InheritableType"));
                    }
                    TypeObj::Builtin(t) => {
                        *t = and(mem::take(t), mono("InheritableType"));
                    }
                }
            } else {
                gen.impls = Some(Box::new(TypeObj::Builtin(mono("InheritableType"))));
            }
            ValueObj::Type(TypeObj::Generated(gen))
        }
        _ => todo!(),
    }
}