1 // This file defines how to compile binary operations
4 #include "../environment.h"
5 #include "../stdlib/datatypes.h"
6 #include "../stdlib/text.h"
7 #include "../stdlib/util.h"
8 #include "../typecheck.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");
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);
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);
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));
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), ")");
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);
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, ")");
123 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
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, ")");
131 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
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, ")");
139 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
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, ")");
147 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
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)");
155 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
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, ")");
163 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
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, ")");
171 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
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, ")");
179 if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
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)
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)
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, ")");
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, ")");
206 code_err(ast, "The 'and' operator isn't supported between ", type_to_text(lhs_t), " and ",
207 type_to_text(rhs_t), " values");
210 return Texts("generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(overall_t), ")");
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, ")");
218 code_err(ast, "The 'or' operator isn't supported between ", type_to_text(lhs_t), " and ",
219 type_to_text(rhs_t), " values");
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, ")");
227 code_err(ast, "The 'xor' operator isn't supported between ", type_to_text(lhs_t), " and ",
228 type_to_text(rhs_t), " values");
231 switch (overall_t->tag) {
233 return Texts("Path$concat(", lhs, ", ", rhs, ")");
236 return Texts("Text$concat(", lhs, ", ", rhs, ")");
239 return Texts("List$concat(", lhs, ", ", rhs, ", sizeof(",
240 compile_type(Match(overall_t, ListType)->item_type), "))");
243 return Texts("Table$with(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")");
246 code_err(ast, "Concatenation isn't supported between ", type_to_text(lhs_t), " and ", type_to_text(rhs_t),
250 default: errx(1, "Not a valid binary operation: %s", ast_to_sexp_str(ast));