summaryrefslogtreecommitdiff
path: root/eval.c
blob: 70333679c18ab730507c13a766a93b1404326a19 (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
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
/* static bool eval_expr_as_float(Expression *e, FloatLiteral *f) { */
/* 	switch (e->kind) { */
/* 	case EXPR_FLOAT_LITERAL: */
/* 		*f = e->floatl; */
/* 		return true; */
/* 	case EXPR_INT_LITERAL: */
/* 		*f = (FloatLiteral)e->intl; */
/* 		return true; */
/* 	} */
/* 	err_print(e->where, "Not implemented yet"); */
/* 	return false; */
/* } */

static bool eval_expr_as_int(Expression *e, Integer *i) {
	/* OPTIM: cache eval'd expression values? (probably only for declarations) */
	switch (e->kind) {
	case EXPR_LITERAL_FLOAT:
		err_print(e->where, "Expected integer, but found floating-point literal.");
		return false;
	case EXPR_LITERAL_INT:
		if (e->intl > (UInteger)INTEGER_MAX) { /* TODO: FIXME */
			err_print(e->where, "Overflow when evaluating integer.");
			return false;
		}
		*i = (Integer)e->intl;
		return true;
	case EXPR_LITERAL_STR:
		err_print(e->where, "Expected integer, but found string literal.");
		return false;
	case EXPR_UNARY_OP:
		switch (e->unary.op) {
		case UNARY_MINUS: {
			Integer of;
			if (!eval_expr_as_int(e->unary.of, &of)) return false;
			*i = -of;
			return true;
		}
		case UNARY_ADDRESS:
			err_print(e->where, "Use of pointer as integer constant.");
			return false;
		}
		break;
	case EXPR_BINARY_OP: {
			
		switch (e->binary.op) {
		case BINARY_PLUS:
		case BINARY_MINUS:
		case BINARY_MUL:
		case BINARY_DIV: {
			Integer lhs, rhs;
			if (!eval_expr_as_int(e->binary.lhs, &lhs)) return false;
			if (!eval_expr_as_int(e->binary.rhs, &rhs)) return false;
			switch (e->binary.op) {
			case BINARY_PLUS:
				*i = lhs + rhs;
				return true;
			case BINARY_MINUS:
				*i = lhs - rhs;
				return true;
			case BINARY_MUL:
				*i = lhs * rhs;
				return true;
			case BINARY_DIV:
				*i = lhs / rhs;
				return true;
			default: assert(0); return false;
			}
		}
	    case BINARY_SET:
		case BINARY_COMMA:
			err_print(e->where, "Expected operator which returns an integer, but got %s", binary_op_to_str(e->binary.op));
			return false;
		case BINARY_AT_INDEX:
			err_print(e->where, "Cannot get index of array at compile time yet.");
			return false;
		}
	} break;
	case EXPR_IDENT: {
		Identifier id = e->ident;
		IdentDecl *id_decl = ident_decl(id);
		if (!id_decl) {
			char *id_str = ident_to_str(id);
			err_print(e->where, "Undeclared identifier: %s", id_str);
			free(id_str);
			return false;
		}
		Declaration *d = id_decl->decl;
		if (location_after(d->where, e->where)) {
			err_print(e->where, "Use of constant before its declaration.");
			info_print(d->where, "Declaration will be here.");
			return false;
		}
		if (!(d->flags & DECL_FLAG_CONST)) {
			err_print(e->where, "Use of non-constant identifier in a constant expression.");
			info_print(d->where, "Declaration was here.");
			return false;
		}
		if (d->type.kind != TYPE_BUILTIN || !type_builtin_is_integer(d->type.builtin)) {
			char *type_str = type_to_str(&d->type);
			err_print(e->where, "Expected integer, but identifier has type %s.", type_str);
			info_print(d->where, "Declaration was here.");
			free(type_str);
			return false;
		}
		/* TODO: tuples */
		eval_expr_as_int(&d->expr, i);
		
		return true;
	} break;
	case EXPR_FN:
		err_print(e->where, "Expected integer, but found function.");
		return false;
	case EXPR_CALL:
		err_print(e->where, "Compile time function calling not supported yet."); /* TODO */
		break;
	case EXPR_BLOCK:
		err_print(e->where, "Block eval not supported yet."); /* TODO */
		break;
	case EXPR_DIRECT:
		switch (e->direct.which) {
		case DIRECT_C:
			err_print(e->where, "Can't run C code at compile time.");
			return false;
		case DIRECT_COUNT: assert(0); break;
		}
		break;
	}
	err_print(e->where, "Not implemented yet");
	return false;
}