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
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
use std::rc::Rc;
use strtab::StringTable;

use super::{checker::SemanticContext, type_system::*};

pub struct BuiltinTypes<'src> {
    pub string: CheckedType<'src>,
}

impl<'src, 'ast> BuiltinTypes<'src> {
    pub fn add_to<'ts>(
        type_system: &'ts mut TypeSystem<'src, 'ast>,
        strtab: &'_ mut StringTable<'src>,
        context: &'_ mut SemanticContext<'_, 'src>,
    ) -> BuiltinTypes<'src> {
        let int_ty = CheckedType::Int;

        let reader_class_id = {
            let mut reader_class_def = ClassDef::new(strtab.intern("$Reader"));
            reader_class_def.comparable = false;
            reader_class_def
                .add_method(ClassMethodDef {
                    name: strtab.intern("read"),
                    body: ClassMethodBody::Builtin(BuiltinMethodBody::SystemInRead),
                    params: vec![],
                    return_ty: int_ty.clone(),
                    is_static: false,
                    is_main: false,
                })
                .unwrap();
            type_system.add_class_def(reader_class_def).unwrap()
        };

        let writer_class_id = {
            let arg_sym = strtab.intern("data");

            // ENHANCEMENT: @hediet: dedup builtin type definitions
            let mut writer_class_def = ClassDef::new(strtab.intern("$Writer"));
            writer_class_def.comparable = false;
            writer_class_def
                .add_method(ClassMethodDef {
                    name: strtab.intern("println"),
                    body: ClassMethodBody::Builtin(BuiltinMethodBody::SystemOutPrintln),
                    params: vec![Rc::new(MethodParamDef::new(arg_sym, int_ty.clone()))],
                    return_ty: CheckedType::Void,
                    is_static: false,
                    is_main: false,
                })
                .unwrap();
            writer_class_def
                .add_method(ClassMethodDef {
                    name: strtab.intern("write"),
                    body: ClassMethodBody::Builtin(BuiltinMethodBody::SystemOutWrite),
                    params: vec![Rc::new(MethodParamDef::new(arg_sym, int_ty.clone()))],
                    return_ty: CheckedType::Void,
                    is_static: false,
                    is_main: false,
                })
                .unwrap();
            writer_class_def
                .add_method(ClassMethodDef {
                    name: strtab.intern("flush"),
                    body: ClassMethodBody::Builtin(BuiltinMethodBody::SystemOutFlush),
                    params: vec![],
                    return_ty: CheckedType::Void,
                    is_static: false,
                    is_main: false,
                })
                .unwrap();
            type_system.add_class_def(writer_class_def).unwrap()
        };

        let system_class_id = {
            let mut system_class_def = ClassDef::new(strtab.intern("$System"));
            system_class_def.comparable = false;
            system_class_def
                .add_field(ClassFieldDef {
                    name: strtab.intern("in"),
                    ty: reader_class_id.into(),
                    can_write: false,
                })
                .unwrap();
            system_class_def
                .add_field(ClassFieldDef {
                    name: strtab.intern("out"),
                    ty: writer_class_id.into(),
                    can_write: false,
                })
                .unwrap();
            type_system.add_class_def(system_class_def).unwrap()
        };

        context
            .global_vars
            .insert(strtab.intern("System"), system_class_id.into());

        let string_class_def = ClassDef::new(strtab.intern("$String"));
        let string_class_id = type_system.add_class_def(string_class_def).unwrap();

        BuiltinTypes {
            string: string_class_id.into(),
        }
    }
}