aboutsummaryrefslogtreecommitdiff
path: root/type.c
blob: 6dd4dd01a9e9b6526bd872c3cf55af759bc849c7 (plain)
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
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include "type.h"


static struct {
	int cap, num;
	struct type **types;
} cache;

static struct type *voidtype;

static void init_cache(void) {
	if (voidtype) return;
	voidtype = malloc(sizeof(struct type));
	voidtype->tag = T_VOID;
	cache.cap = 8;
	cache.num = 0;
	cache.types = malloc(cache.cap * sizeof(struct type*));
}

void type_cache_cleanup(void) {
	for (int i = 0; i < cache.num; i++) {
		free(cache.types[i]);
	}
	free(cache.types);
	free(voidtype);
}

static void cache_add(struct type *type) {
	if (cache.num == cache.cap) {
		cache.cap *= 2;
		cache.types = realloc(cache.types, cache.cap * sizeof(struct type*));
	}
	cache.types[cache.num++] = type;
}


struct type* type_int(int size) {
	init_cache();
	for (int i = 0; i < cache.num; i++) {
		if (cache.types[i]->tag == T_INT && cache.types[i]->size == size) {
			return cache.types[i];
		}
	}
	struct type *type = malloc(sizeof(struct type));
	type->tag = T_INT;
	type->size = size;
	cache_add(type);
	return type;
}

struct type* type_void(void) {
	return voidtype;
}

struct type* type_ptr(struct type *target) {
	init_cache();
	for (int i = 0; i < cache.num; i++) {
		if (cache.types[i]->tag == T_PTR && cache.types[i]->target == target) {
			return cache.types[i];
		}
	}
	struct type *type = malloc(sizeof(struct type));
	type->tag = T_PTR;
	type->target = target;
	cache_add(type);
	return type;
}

void type_print(struct type *type, FILE *f) {
	switch (type->tag) {
		case T_INT: fprintf(f, "i%d", type->size); break;
		case T_VOID: fprintf(f, "void"); break;
		case T_PTR: type_print(type->target, f); fprintf(f, "*"); break;
		default: assert(false);
	}
}