code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(253 lines)
1 // This file defines how to compile binary operations
3 #include "../ast.h"
4 #include "../environment.h"
5 #include "../stdlib/datatypes.h"
6 #include "../stdlib/text.h"
7 #include "../stdlib/util.h"
8 #include "../typecheck.h"
9 #include "../types.h"
10 #include "compilation.h"
12 static PUREFUNC Text_t compile_unsigned_type(type_t *t) {
13 if (t->tag != IntType) errx(1, "Not an int type, so unsigned doesn't make sense!");
14 switch (Match(t, IntType)->bits) {
15 case TYPE_IBITS8: return Text("uint8_t");
16 case TYPE_IBITS16: return Text("uint16_t");
17 case TYPE_IBITS32: return Text("uint32_t");
18 case TYPE_IBITS64: return Text("uint64_t");
19 default: errx(1, "Invalid integer bit size");
21 return EMPTY_TEXT;
24 public
25 Text_t compile_binary_op(env_t *env, ast_t *ast) {
26 binary_operands_t binop = BINARY_OPERANDS(ast);
27 type_t *lhs_t = get_type(env, binop.lhs);
28 type_t *rhs_t = get_type(env, binop.rhs);
29 type_t *overall_t = get_type(env, ast);
31 binding_t *b = get_metamethod_binding(env, ast->tag, binop.lhs, binop.rhs, overall_t);
32 if (!b) b = get_metamethod_binding(env, ast->tag, binop.rhs, binop.lhs, overall_t);
33 if (b) {
34 arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
35 DeclareMatch(fn, b->type, FunctionType);
36 return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
39 if (ast->tag == Multiply && is_numeric_type(lhs_t)) {
40 b = get_namespace_binding(env, binop.rhs, "scaled_by");
41 if (b && b->type->tag == FunctionType) {
42 DeclareMatch(fn, b->type, FunctionType);
43 if (type_eq(fn->ret, rhs_t)) {
44 arg_ast_t *args = new (arg_ast_t, .value = binop.rhs, .next = new (arg_ast_t, .value = binop.lhs));
45 if (is_valid_call(env, fn->args, args, (call_opts_t){.promotion = true}))
46 return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
49 } else if (ast->tag == Multiply && is_numeric_type(rhs_t)) {
50 b = get_namespace_binding(env, binop.lhs, "scaled_by");
51 if (b && b->type->tag == FunctionType) {
52 DeclareMatch(fn, b->type, FunctionType);
53 if (type_eq(fn->ret, lhs_t)) {
54 arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
55 if (is_valid_call(env, fn->args, args, (call_opts_t){.promotion = true}))
56 return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
59 } else if (ast->tag == Divide && is_numeric_type(rhs_t)) {
60 b = get_namespace_binding(env, binop.lhs, "divided_by");
61 if (b && b->type->tag == FunctionType) {
62 DeclareMatch(fn, b->type, FunctionType);
63 if (type_eq(fn->ret, lhs_t)) {
64 arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
65 if (is_valid_call(env, fn->args, args, (call_opts_t){.promotion = true}))
66 return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
69 } else if ((ast->tag == Divide || ast->tag == Mod || ast->tag == Mod1) && is_numeric_type(rhs_t)) {
70 b = get_namespace_binding(env, binop.lhs, binop_info[ast->tag].method_name);
71 if (b && b->type->tag == FunctionType) {
72 DeclareMatch(fn, b->type, FunctionType);
73 if (type_eq(fn->ret, lhs_t)) {
74 arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
75 if (is_valid_call(env, fn->args, args, (call_opts_t){.promotion = true}))
76 return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
81 if (ast->tag == Or && lhs_t->tag == OptionalType) {
82 if (rhs_t->tag == AbortType || rhs_t->tag == ReturnType) {
83 return Texts("({ ", compile_declaration(lhs_t, Text("lhs")), " = ", compile(env, binop.lhs), "; ", "if (",
84 check_none(lhs_t, Text("lhs")), ") ", compile_statement(env, binop.rhs), " ",
85 optional_into_nonnone(lhs_t, Text("lhs")), "; })");
88 if (is_incomplete_type(rhs_t)) {
89 type_t *complete = most_complete_type(rhs_t, Match(lhs_t, OptionalType)->type);
90 if (complete == NULL)
91 code_err(binop.rhs, "I don't know how to convert a ", type_to_text(rhs_t), " to a ",
92 type_to_text(Match(lhs_t, OptionalType)->type));
93 rhs_t = complete;
96 if (rhs_t->tag == OptionalType && type_eq(lhs_t, rhs_t)) {
97 return Texts("({ ", compile_declaration(lhs_t, Text("lhs")), " = ", compile(env, binop.lhs), "; ",
98 check_none(lhs_t, Text("lhs")), " ? ", compile(env, binop.rhs), " : lhs; })");
99 } else if (rhs_t->tag != OptionalType && type_eq(Match(lhs_t, OptionalType)->type, rhs_t)) {
100 return Texts("({ ", compile_declaration(lhs_t, Text("lhs")), " = ", compile(env, binop.lhs), "; ",
101 check_none(lhs_t, Text("lhs")), " ? ", compile(env, binop.rhs), " : ",
102 optional_into_nonnone(lhs_t, Text("lhs")), "; })");
103 } else if (rhs_t->tag == BoolType) {
104 return Texts("((!", check_none(lhs_t, compile(env, binop.lhs)), ") || ", compile(env, binop.rhs), ")");
105 } else {
106 code_err(ast, "I don't know how to do an 'or' operation between ", type_to_text(lhs_t), " and ",
107 type_to_text(rhs_t));
111 Text_t lhs = compile_to_type(env, binop.lhs, overall_t);
112 Text_t rhs = compile_to_type(env, binop.rhs, overall_t);
114 switch (ast->tag) {
115 case Power: {
116 if (overall_t->tag != NumType)
117 code_err(ast, "Exponentiation is only supported for Num types, not ", type_to_text(overall_t));
118 if (overall_t->tag == NumType && Match(overall_t, NumType)->bits == TYPE_NBITS32)
119 return Texts("powf(", lhs, ", ", rhs, ")");
120 else return Texts("pow(", lhs, ", ", rhs, ")");
122 case Multiply: {
123 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
124 code_err(ast,
125 "Math operations are only supported for values of the same "
126 "numeric type, not ",
127 type_to_text(lhs_t), " and ", type_to_text(rhs_t));
128 return Texts("(", lhs, " * ", rhs, ")");
130 case Divide: {
131 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
132 code_err(ast,
133 "Math operations are only supported for values of the same "
134 "numeric type, not ",
135 type_to_text(lhs_t), " and ", type_to_text(rhs_t));
136 return Texts("(", lhs, " / ", rhs, ")");
138 case Mod: {
139 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
140 code_err(ast,
141 "Math operations are only supported for values of the same "
142 "numeric type, not ",
143 type_to_text(lhs_t), " and ", type_to_text(rhs_t));
144 return Texts("(", lhs, " % ", rhs, ")");
146 case Mod1: {
147 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
148 code_err(ast,
149 "Math operations are only supported for values of the same "
150 "numeric type, not ",
151 type_to_text(lhs_t), " and ", type_to_text(rhs_t));
152 return Texts("((((", lhs, ")-1) % (", rhs, ")) + 1)");
154 case Plus: {
155 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
156 code_err(ast,
157 "Math operations are only supported for values of the same "
158 "numeric type, not ",
159 type_to_text(lhs_t), " and ", type_to_text(rhs_t));
160 return Texts("(", lhs, " + ", rhs, ")");
162 case Minus: {
163 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
164 code_err(ast,
165 "Math operations are only supported for values of the same "
166 "numeric type, not ",
167 type_to_text(lhs_t), " and ", type_to_text(rhs_t));
168 return Texts("(", lhs, " - ", rhs, ")");
170 case LeftShift: {
171 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
172 code_err(ast,
173 "Math operations are only supported for values of the same "
174 "numeric type, not ",
175 type_to_text(lhs_t), " and ", type_to_text(rhs_t));
176 return Texts("(", lhs, " << ", rhs, ")");
178 case RightShift: {
179 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
180 code_err(ast,
181 "Math operations are only supported for values of the same "
182 "numeric type, not ",
183 type_to_text(lhs_t), " and ", type_to_text(rhs_t));
184 return Texts("(", lhs, " >> ", rhs, ")");
186 case UnsignedLeftShift: {
187 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
188 code_err(ast,
189 "Math operations are only supported for values of the same "
190 "numeric type, not ",
191 type_to_text(lhs_t), " and ", type_to_text(rhs_t));
192 return Texts("(", compile_type(overall_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " << ", rhs, ")");
194 case UnsignedRightShift: {
195 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
196 code_err(ast,
197 "Math operations are only supported for values of the same "
198 "numeric type, not ",
199 type_to_text(lhs_t), " and ", type_to_text(rhs_t));
200 return Texts("(", compile_type(overall_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " >> ", rhs, ")");
202 case And: {
203 if (overall_t->tag == BoolType) return Texts("(", lhs, " && ", rhs, ")");
204 else if (overall_t->tag == IntType || overall_t->tag == ByteType) return Texts("(", lhs, " & ", rhs, ")");
205 else
206 code_err(ast, "The 'and' operator isn't supported between ", type_to_text(lhs_t), " and ",
207 type_to_text(rhs_t), " values");
209 case Compare: {
210 return Texts("generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(overall_t), ")");
212 case Or: {
213 if (overall_t->tag == BoolType) {
214 return Texts("(", lhs, " || ", rhs, ")");
215 } else if (overall_t->tag == IntType || overall_t->tag == ByteType) {
216 return Texts("(", lhs, " | ", rhs, ")");
217 } else {
218 code_err(ast, "The 'or' operator isn't supported between ", type_to_text(lhs_t), " and ",
219 type_to_text(rhs_t), " values");
222 case Xor: {
223 // TODO: support optional values in `xor` expressions
224 if (overall_t->tag == BoolType || overall_t->tag == IntType || overall_t->tag == ByteType)
225 return Texts("(", lhs, " ^ ", rhs, ")");
226 else
227 code_err(ast, "The 'xor' operator isn't supported between ", type_to_text(lhs_t), " and ",
228 type_to_text(rhs_t), " values");
230 case Concat: {
231 switch (overall_t->tag) {
232 case PathType: {
233 return Texts("Path$concat(", lhs, ", ", rhs, ")");
235 case TextType: {
236 return Texts("Text$concat(", lhs, ", ", rhs, ")");
238 case ListType: {
239 return Texts("List$concat(", lhs, ", ", rhs, ", sizeof(",
240 compile_type(Match(overall_t, ListType)->item_type), "))");
242 case TableType: {
243 return Texts("Table$with(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")");
245 default:
246 code_err(ast, "Concatenation isn't supported between ", type_to_text(lhs_t), " and ", type_to_text(rhs_t),
247 " values");
250 default: errx(1, "Not a valid binary operation: %s", ast_to_sexp_str(ast));
252 return EMPTY_TEXT;