code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(99 lines)
1 // This file defines how to compile indexing like `list[i]` or `ptr[]`
3 #include <stdbool.h>
5 #include "../ast.h"
6 #include "../config.h"
7 #include "../environment.h"
8 #include "../stdlib/text.h"
9 #include "../stdlib/util.h"
10 #include "../typecheck.h"
11 #include "compilation.h"
13 public
14 Text_t compile_indexing(env_t *env, ast_t *ast, bool checked) {
15 DeclareMatch(indexing, ast, Index);
16 type_t *indexed_type = get_type(env, indexing->indexed);
17 if (!indexing->index) {
18 if (indexed_type->tag != PointerType)
19 code_err(ast, "Only pointers can use the '[]' operator to "
20 "dereference "
21 "the entire value.");
22 DeclareMatch(ptr, indexed_type, PointerType);
23 if (ptr->pointed->tag == ListType) {
24 return Texts("*({ List_t *list = ", compile(env, indexing->indexed), "; LIST_INCREF(*list); list; })");
25 } else if (ptr->pointed->tag == TableType) {
26 return Texts("*({ Table_t *t = ", compile(env, indexing->indexed), "; TABLE_INCREF(*t); t; })");
27 } else {
28 return Texts("*(", compile(env, indexing->indexed), ")");
32 type_t *container_t = value_type(indexed_type);
33 type_t *index_t = get_type(env, indexing->index);
34 if (container_t->tag == ListType) {
35 if (index_t->tag != IntType && index_t->tag != BigIntType && index_t->tag != ByteType)
36 code_err(indexing->index, "Lists can only be indexed by integers, not ", type_to_text(index_t));
37 type_t *item_type = Match(container_t, ListType)->item_type;
38 Text_t list = compile_to_pointer_depth(env, indexing->indexed, 0, false);
39 Text_t index_code =
40 indexing->index->tag == Int
41 ? compile_int_to_type(env, indexing->index, Type(IntType, .bits = TYPE_IBITS64))
42 : (index_t->tag == BigIntType ? Texts("Int64$from_int(", compile(env, indexing->index), ", no)")
43 : Texts("(Int64_t)(", compile(env, indexing->index), ")"));
44 if (checked) {
45 int64_t start = (int64_t)(ast->start - ast->file->text), end = (int64_t)(ast->end - ast->file->text);
46 Text_t code = Texts("List_get_checked(", list, ", ", index_code, ", ", compile_type(item_type), ", ", start,
47 ", ", end, ")");
48 if (item_type->tag == OptionalType) {
49 int64_t line = get_line_number(ast->file, ast->start);
50 return Texts("({ ", compile_declaration(item_type, Text("opt")), " = ", code, "; ", "if unlikely (",
51 check_none(item_type, Text("opt")), ")\n", "#line ", line, "\n", "fail_source(",
52 quoted_str(ast->file->filename), ", ", start, ", ", end, ", ",
53 "Text(\"This was expected to be a value, but it's `none`\\n\"));\n",
54 optional_into_nonnone(item_type, Text("opt")), "; })");
56 return code;
57 } else if (item_type->tag == OptionalType) {
58 return Texts("List_get(", list, ", ", index_code, ", ", compile_type(item_type), ", value, value,",
59 compile_none(item_type), ")");
60 } else {
61 return Texts("List_get(", list, ", ", index_code, ", ", compile_type(item_type), ", value, ",
62 promote_to_optional(item_type, Text("value")), ", ", compile_none(item_type), ")");
64 } else if (container_t->tag == TableType) {
65 DeclareMatch(table_type, container_t, TableType);
66 if (table_type->default_value) {
67 return Texts("Table$get_or_default(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
68 compile_type(table_type->key_type), ", ", compile_type(table_type->value_type), ", ",
69 compile_to_type(env, indexing->index, table_type->key_type), ", ",
70 compile_to_type(env, table_type->default_value, table_type->value_type), ", ",
71 compile_type_info(container_t), ")");
72 } else if (checked) {
73 int64_t start = (int64_t)(ast->start - ast->file->text), end = (int64_t)(ast->end - ast->file->text);
74 return Texts("Table$get_checked(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
75 compile_type(table_type->key_type), ", ", compile_type(table_type->value_type), ", ",
76 compile(env, indexing->index), ", ", start, ", ", end, ", ", compile_type_info(container_t),
77 ")");
78 } else {
79 return Texts("Table$get_optional(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
80 compile_type(table_type->key_type), ", ", compile_type(table_type->value_type), ", ",
81 compile_to_type(env, indexing->index, table_type->key_type),
82 ", "
83 "_, ",
84 promote_to_optional(table_type->value_type, Text("(*_)")), ", ",
85 compile_none(table_type->value_type), ", ", compile_type_info(container_t), ")");
87 } else if (container_t->tag == TextType) {
88 if (checked) {
89 int64_t start = (int64_t)(ast->start - ast->file->text), end = (int64_t)(ast->end - ast->file->text);
90 return Texts("Text$cluster_checked(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
91 compile_to_type(env, indexing->index, Type(BigIntType)), ", ", start, ", ", end, ")");
92 } else {
93 return Texts("Text$cluster(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
94 compile_to_type(env, indexing->index, Type(BigIntType)), ")");
96 } else {
97 code_err(ast, "Indexing is not supported for type: ", type_to_text(container_t));