aboutsummaryrefslogtreecommitdiff
path: root/compiler/types.cup
blob: 9b0d822ddf5abcd0be32693cc881acc1dbc5f7da (plain) (blame)
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import "std/common.cup"
import "std/vector.cup"

enum BaseType {
    TYPE_VOID,
    TYPE_ANY,

    TYPE_PTR,
    TYPE_ARRAY,
    TYPE_STRUCT,
    TYPE_UNION,

    TYPE_INT,
    TYPE_CHAR,
};

struct Type {
    typ: int;
    ptr: Type*;
    struct_name: char*;
    size: int;
    array_size: int;
    fields: Vector*; // Vector<Variable*>;
};

fn size_for_base_type(type: int): int {
    if (type == TYPE_INT) return 8;
    if (type == TYPE_PTR) return 8;
    if (type == TYPE_CHAR) return 1;
    // Need to be initialized explicitly for compound types 
    return 0; 
}

fn size_for_type(typ: Type*): int {
    if (typ.typ == TYPE_INT) return 8;
    if (typ.typ == TYPE_PTR) return 8;
    if (typ.typ == TYPE_CHAR) return 1;
    if (typ.typ == TYPE_ARRAY) return typ.array_size * size_for_type(typ.ptr);
    if (typ.typ == TYPE_STRUCT) return typ.size;
    if (typ.typ == TYPE_UNION) return typ.size;
    if (typ.typ == TYPE_VOID) return 0;
    if (typ.typ == TYPE_ANY) return 8;
    die("Unknown type in size_for_type");
}

let _type_int: Type* = null;
let _type_char: Type* = null;
let _type_void: Type* = null;
let _type_any: Type* = null;

fn type_new(typ: int): Type* {
    if (_type_int == null) { _type_int = malloc(sizeof(Type)); _type_int.typ = TYPE_INT; _type_int.size = 8; }
    if (_type_char == null) { _type_char = malloc(sizeof(Type)); _type_char.typ = TYPE_CHAR; _type_char.size = 1; }
    if (_type_void == null) { _type_void = malloc(sizeof(Type)); _type_void.typ = TYPE_VOID; _type_void.size = 0; }
    if (_type_any == null) { _type_any = malloc(sizeof(Type)); _type_any.typ = TYPE_ANY; _type_any.size = 8; }
    
    if (typ == TYPE_INT) return _type_int;
    if (typ == TYPE_CHAR) return _type_char;
    if (typ == TYPE_VOID) return _type_void;
    if (typ == TYPE_ANY) return _type_any;

    let t: Type* = malloc(sizeof(Type));
    t.typ = typ;
    t.size = size_for_base_type(typ);
    return t;
}

fn type_new_ptr(typ: int): Type* {
    let ptr = type_new(TYPE_PTR);
    ptr.ptr = type_new(typ);
    return ptr;
}

// This is named differently because it performs an allocation
fn create_type_string(typ: Type *): char* {
    let buf: char* = malloc(32);
    while (typ.typ == TYPE_PTR || typ.typ == TYPE_ARRAY) {
        strcat(buf, typ.typ == TYPE_PTR ? "*" : "[]");
        typ = typ.ptr;
    }

         if (typ.typ == TYPE_INT) strcat(buf, "int");
    else if (typ.typ == TYPE_CHAR) strcat(buf, "char");
    else if (typ.typ == TYPE_VOID) strcat(buf, "void");
    else if (typ.typ == TYPE_ANY) strcat(buf, "any");
    else if (typ.typ == TYPE_STRUCT) strcat(buf, typ.struct_name);
    else  die("create_type_string: unknown type");

    return buf;
}

fn is_int_type(typ: Type*): int {
    if (typ.typ == TYPE_INT) return true;
    if (typ.typ == TYPE_CHAR) return true;
    return false;
}


fn types_equal(a: Type*, b: Type*): int {
    if (a == null && b == null)
        return true;
    if (a == null || b == null)
        return false;
    if (a.typ == TYPE_ANY || b.typ == TYPE_ANY)
        return true;
    return a.typ == b.typ && types_equal(a.ptr, b.ptr);
}

fn is_convertible(from: Type*, to: Type*): int {
    if (from.typ == TYPE_ANY || to.typ == TYPE_ANY)
        return true;

    // Allow converstions to and from void* to any other pointer type
    if (from.typ == TYPE_PTR && to.typ == TYPE_PTR)
        if (from.ptr.typ == TYPE_VOID || to.ptr.typ == TYPE_VOID)
            return true;

    // TODO: Should we rause a warning if the target type is narrower
    //       than the source type?
    if (is_int_type(from) && is_int_type(to))
        return true;
    return types_equal(from, to);
}

fn is_struct_or_structptr(typ: Type*): int {
    if (typ.typ == TYPE_STRUCT || typ.typ == TYPE_UNION)
        return true;
    if (typ.typ == TYPE_PTR)
        if (typ.ptr.typ == TYPE_STRUCT || typ.ptr.typ == TYPE_UNION)
            return true;
    return false;
}