code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(276 lines)
1 // This file defines logic for compiling expressions
3 #include "expressions.h"
4 #include "../ast.h"
5 #include "../config.h"
6 #include "../environment.h"
7 #include "../stdlib/text.h"
8 #include "../stdlib/util.h"
9 #include "../typecheck.h"
10 #include "compilation.h"
12 public
13 Text_t compile_maybe_incref(env_t *env, ast_t *ast, type_t *t) {
14 if (!has_refcounts(t) || !can_be_mutated(env, ast)) {
15 return compile_to_type(env, ast, t);
18 // When using a struct as a value, we need to increment the refcounts of the inner fields as well:
19 if (t->tag == StructType) {
20 // If the struct is non-idempotent, we have to stash it in a local var first
21 if (is_idempotent(ast)) {
22 Text_t code = Texts("((", compile_type(t), "){");
23 for (arg_t *field = Match(t, StructType)->fields; field; field = field->next) {
24 Text_t val = compile_maybe_incref(env, WrapAST(ast, FieldAccess, .fielded = ast, .field = field->name),
25 get_arg_type(env, field));
26 code = Texts(code, val);
27 if (field->next) code = Texts(code, ", ");
29 return Texts(code, "})");
30 } else {
31 static int64_t tmp_index = 1;
32 Text_t tmp_name = Texts("_tmp", tmp_index);
33 tmp_index += 1;
34 Text_t code = Texts("({ ", compile_declaration(t, tmp_name), " = ", compile_to_type(env, ast, t), "; ",
35 "((", compile_type(t), "){");
36 ast_t *tmp = WrapLiteralCode(ast, tmp_name, .type = t);
37 for (arg_t *field = Match(t, StructType)->fields; field; field = field->next) {
38 Text_t val = compile_maybe_incref(env, WrapAST(ast, FieldAccess, .fielded = tmp, .field = field->name),
39 get_arg_type(env, field));
40 code = Texts(code, val);
41 if (field->next) code = Texts(code, ", ");
43 return Texts(code, "}); })");
45 } else if (t->tag == ListType && ast->tag != List && can_be_mutated(env, ast) && type_eq(get_type(env, ast), t)) {
46 return Texts("LIST_COPY(", compile_to_type(env, ast, t), ")");
47 } else if (t->tag == TableType && ast->tag != Table && can_be_mutated(env, ast) && type_eq(get_type(env, ast), t)) {
48 return Texts("TABLE_COPY(", compile_to_type(env, ast, t), ")");
50 return compile_to_type(env, ast, t);
53 public
54 Text_t compile_empty(type_t *t) {
55 if (t == NULL) compiler_err(NULL, NULL, NULL, "I can't compile a value with no type");
57 if (t->tag == OptionalType) return compile_none(t);
59 switch (t->tag) {
60 case BigIntType: return Text("I(0)");
61 case IntType: {
62 switch (Match(t, IntType)->bits) {
63 case TYPE_IBITS8: return Text("I8(0)");
64 case TYPE_IBITS16: return Text("I16(0)");
65 case TYPE_IBITS32: return Text("I32(0)");
66 case TYPE_IBITS64: return Text("I64(0)");
67 default: errx(1, "Invalid integer bit size");
69 break;
71 case ByteType: return Text("((Byte_t)0)");
72 case BoolType: return Text("((Bool_t)no)");
73 case ListType: return Text("EMPTY_LIST");
74 case TableType: return Text("EMPTY_TABLE");
75 case TextType: return Text("EMPTY_TEXT");
76 case CStringType: return Text("\"\"");
77 case PathType: return Text("NONE_PATH");
78 case PointerType: {
79 DeclareMatch(ptr, t, PointerType);
80 Text_t empty_pointed = compile_empty(ptr->pointed);
81 return empty_pointed.length == 0 ? EMPTY_TEXT
82 : Texts(ptr->is_stack ? Text("stack(") : Text("heap("), empty_pointed, ")");
84 case NumType: {
85 return Match(t, NumType)->bits == TYPE_NBITS32 ? Text("N32(0.0f)") : Text("N64(0.0)");
87 case StructType: return compile_empty_struct(t);
88 case EnumType: return compile_empty_enum(t);
89 default: return EMPTY_TEXT;
91 return EMPTY_TEXT;
94 Text_t compile(env_t *env, ast_t *ast) {
95 switch (ast->tag) {
96 case None: {
97 type_t *type = Match(ast, None)->type;
98 if (type == NULL) code_err(ast, "I can't figure out what this `none`'s type is!");
99 return compile_none(non_optional(type));
101 case Bool: return Match(ast, Bool)->b ? Text("yes") : Text("no");
102 case Var: {
103 binding_t *b = get_binding(env, Match(ast, Var)->name);
104 if (b) return b->code.length > 0 ? b->code : Texts("_$", Match(ast, Var)->name);
105 // return Texts("_$", Match(ast, Var)->name);
106 code_err(ast, "I don't know of any variable by this name");
108 case Int: return compile_int(ast);
109 case Num: {
110 return Text$from_str(String(hex_double(Match(ast, Num)->n)));
112 case Not: {
113 ast_t *value = Match(ast, Not)->value;
114 type_t *t = get_type(env, value);
116 binding_t *b = get_namespace_binding(env, value, "negated");
117 if (b && b->type->tag == FunctionType) {
118 DeclareMatch(fn, b->type, FunctionType);
119 if (fn->args && can_compile_to_type(env, value, get_arg_type(env, fn->args)))
120 return Texts(b->code, "(", compile_arguments(env, ast, fn->args, new (arg_ast_t, .value = value)), ")");
123 if (t->tag == BoolType) return Texts("!(", compile(env, value), ")");
124 else if (t->tag == IntType || t->tag == ByteType) return Texts("~(", compile(env, value), ")");
125 else if (t->tag == ListType) return Texts("((", compile(env, value), ").length == 0)");
126 else if (t->tag == TableType) return Texts("((", compile(env, value), ").entries.length == 0)");
127 else if (t->tag == TextType) return Texts("(", compile(env, value), ".length == 0)");
128 else if (t->tag == OptionalType) return check_none(t, compile(env, value));
130 code_err(ast, "I don't know how to negate values of type ", type_to_text(t));
132 case Negative: {
133 ast_t *value = Match(ast, Negative)->value;
134 type_t *t = get_type(env, value);
135 binding_t *b = get_namespace_binding(env, value, "negative");
136 if (b && b->type->tag == FunctionType) {
137 DeclareMatch(fn, b->type, FunctionType);
138 if (fn->args && can_compile_to_type(env, value, get_arg_type(env, fn->args)))
139 return Texts(b->code, "(", compile_arguments(env, ast, fn->args, new (arg_ast_t, .value = value)), ")");
142 if (t->tag == IntType || t->tag == NumType) return Texts("-(", compile(env, value), ")");
144 code_err(ast, "I don't know how to get the negative value of type ", type_to_text(t));
146 case HeapAllocate:
147 case StackReference: return compile_typed_allocation(env, ast, get_type(env, ast));
148 case NonOptional: return compile_non_optional(env, ast);
149 case Power:
150 case Multiply:
151 case Divide:
152 case Mod:
153 case Mod1:
154 case Plus:
155 case Minus:
156 case Concat:
157 case LeftShift:
158 case UnsignedLeftShift:
159 case RightShift:
160 case UnsignedRightShift:
161 case And:
162 case Or:
163 case Xor: return compile_binary_op(env, ast);
164 case Equals:
165 case NotEquals:
166 case LessThan:
167 case LessThanOrEquals:
168 case GreaterThan:
169 case GreaterThanOrEquals:
170 case Compare: return compile_comparison(env, ast);
171 case TextLiteral:
172 case TextJoin: return compile_text_ast(env, ast);
173 case Path: {
174 return Texts("Path(", compile_text_literal(Text$from_str(Match(ast, Path)->path)), ")");
176 case Block: return compile_block_expression(env, ast);
177 case Min:
178 case Max: {
179 type_t *t = get_type(env, ast);
180 ast_t *key = ast->tag == Min ? Match(ast, Min)->key : Match(ast, Max)->key;
181 ast_t *lhs = ast->tag == Min ? Match(ast, Min)->lhs : Match(ast, Max)->lhs;
182 ast_t *rhs = ast->tag == Min ? Match(ast, Min)->rhs : Match(ast, Max)->rhs;
183 const char *key_name = ast->tag == Min ? "_min_" : "_max_";
184 if (key == NULL) key = FakeAST(Var, key_name);
186 env_t *expr_env = fresh_scope(env);
187 set_binding(expr_env, key_name, t, Text("ternary$lhs"));
188 Text_t lhs_key = compile(expr_env, key);
190 set_binding(expr_env, key_name, t, Text("ternary$rhs"));
191 Text_t rhs_key = compile(expr_env, key);
193 type_t *key_t = get_type(expr_env, key);
194 Text_t comparison;
195 if (key_t->tag == BigIntType)
196 comparison =
197 Texts("(Int$compare_value(", lhs_key, ", ", rhs_key, ")", (ast->tag == Min ? "<=" : ">="), "0)");
198 else if (key_t->tag == IntType || key_t->tag == NumType || key_t->tag == BoolType || key_t->tag == PointerType
199 || key_t->tag == ByteType)
200 comparison = Texts("((", lhs_key, ")", (ast->tag == Min ? "<=" : ">="), "(", rhs_key, "))");
201 else
202 comparison = Texts("generic_compare(stack(", lhs_key, "), stack(", rhs_key, "), ", compile_type_info(key_t),
203 ")", (ast->tag == Min ? "<=" : ">="), "0");
205 return Texts("({\n", compile_type(t), " ternary$lhs = ", compile(env, lhs),
206 ", ternary$rhs = ", compile(env, rhs), ";\n", comparison,
207 " ? ternary$lhs : ternary$rhs;\n"
208 "})");
210 case List: {
211 DeclareMatch(list, ast, List);
212 if (!list->items) return Text("EMPTY_LIST");
214 type_t *list_type = get_type(env, ast);
215 return compile_typed_list(env, ast, list_type);
217 case Table: {
218 DeclareMatch(table, ast, Table);
219 if (!table->entries) {
220 Text_t code = Text("((Table_t){.entries=EMPTY_LIST");
221 if (table->fallback) code = Texts(code, ", .fallback=heap(", compile(env, table->fallback), ")");
222 return Texts(code, "})");
225 type_t *table_type = get_type(env, ast);
226 return compile_typed_table(env, ast, table_type);
228 case Comprehension: {
229 ast_t *base = Match(ast, Comprehension)->expr;
230 while (base->tag == Comprehension)
231 base = Match(ast, Comprehension)->expr;
232 if (base->tag == TableEntry) return compile(env, WrapAST(ast, Table, .entries = new (ast_list_t, .ast = ast)));
233 else return compile(env, WrapAST(ast, List, .items = new (ast_list_t, .ast = ast)));
235 case Lambda: return compile_lambda(env, ast);
236 case MethodCall: return compile_method_call(env, ast);
237 case FunctionCall: return compile_function_call(env, ast);
238 case ExplicitlyTyped: {
239 return compile_to_type(env, Match(ast, ExplicitlyTyped)->ast, get_type(env, ast));
241 case When: return compile_when_expression(env, ast);
242 case If: return compile_if_expression(env, ast);
243 case Reduction: return compile_reduction(env, ast);
244 case FieldAccess: return compile_field_access(env, ast);
245 case Index: return compile_indexing(env, ast, false);
246 case InlineCCode: {
247 type_t *t = get_type(env, ast);
248 if (Match(ast, InlineCCode)->type_ast != NULL) return Texts("({", compile_statement(env, ast), "; })");
249 else if (t->tag == VoidType) return Texts("{\n", compile_statement(env, ast), "\n}");
250 else return compile_statement(env, ast);
252 case Use: code_err(ast, "Compiling 'use' as expression!");
253 case Defer: code_err(ast, "Compiling 'defer' as expression!");
254 case TableEntry: code_err(ast, "Table entries should not be compiled directly");
255 case Declare:
256 case Assign:
257 case UPDATE_CASES:
258 case For:
259 case While:
260 case Repeat:
261 case StructDef:
262 case LangDef:
263 case EnumDef:
264 case FunctionDef:
265 case ConvertDef:
266 case Skip:
267 case Stop:
268 case Pass:
269 case Return:
270 case DebugLog:
271 case Assert: code_err(ast, "This is not a valid expression");
272 case Unknown:
273 default: code_err(ast, "Unknown AST: ", ast_to_sexp_str(ast));
275 return EMPTY_TEXT;