summaryrefslogtreecommitdiff
path: root/eval.c
blob: 995871884a4ce2a6d50be4952092044345b5f740 (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
/* 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_FLOAT_LITERAL:
		err_print(e->where, "Expected integer, but found floating-point literal.");
		return false;
	case EXPR_INT_LITERAL:
		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_STR_LITERAL:
		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;
		}
		}
		break;
	case EXPR_BINARY_OP: {
			
		switch (e->binary.op) {
		case BINARY_PLUS:
		case BINARY_MINUS: {
			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;
			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_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;
}