aboutsummaryrefslogtreecommitdiff
path: root/src/compile/indexing.c
blob: 1510e9244b2d2aecacd8e623a0179ff3551aff53 (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
// This file defines how to compile indexing like `list[i]` or `ptr[]`

#include "../ast.h"
#include "../config.h"
#include "../environment.h"
#include "../stdlib/text.h"
#include "../stdlib/util.h"
#include "../typecheck.h"
#include "compilation.h"

public
Text_t compile_indexing(env_t *env, ast_t *ast) {
    DeclareMatch(indexing, ast, Index);
    type_t *indexed_type = get_type(env, indexing->indexed);
    if (!indexing->index) {
        if (indexed_type->tag != PointerType)
            code_err(ast, "Only pointers can use the '[]' operator to "
                          "dereference "
                          "the entire value.");
        DeclareMatch(ptr, indexed_type, PointerType);
        if (ptr->pointed->tag == ListType) {
            return Texts("*({ List_t *list = ", compile(env, indexing->indexed), "; LIST_INCREF(*list); list; })");
        } else if (ptr->pointed->tag == TableType || ptr->pointed->tag == SetType) {
            return Texts("*({ Table_t *t = ", compile(env, indexing->indexed), "; TABLE_INCREF(*t); t; })");
        } else {
            return Texts("*(", compile(env, indexing->indexed), ")");
        }
    }

    type_t *container_t = value_type(indexed_type);
    type_t *index_t = get_type(env, indexing->index);
    if (container_t->tag == ListType) {
        if (index_t->tag != IntType && index_t->tag != BigIntType && index_t->tag != ByteType)
            code_err(indexing->index, "Lists can only be indexed by integers, not ", type_to_str(index_t));
        type_t *item_type = Match(container_t, ListType)->item_type;
        Text_t list = compile_to_pointer_depth(env, indexing->indexed, 0, false);
        file_t *f = indexing->index->file;
        Text_t index_code =
            indexing->index->tag == Int
                ? compile_int_to_type(env, indexing->index, Type(IntType, .bits = TYPE_IBITS64))
                : (index_t->tag == BigIntType ? Texts("Int64$from_int(", compile(env, indexing->index), ", no)")
                                              : Texts("(Int64_t)(", compile(env, indexing->index), ")"));
        if (indexing->unchecked)
            return Texts("List_get_unchecked(", compile_type(item_type), ", ", list, ", ", index_code, ")");
        else
            return Texts("List_get(", compile_type(item_type), ", ", list, ", ", index_code, ", ",
                         (int64_t)(indexing->index->start - f->text), ", ", (int64_t)(indexing->index->end - f->text),
                         ")");
    } else if (container_t->tag == TableType) {
        DeclareMatch(table_type, container_t, TableType);
        if (indexing->unchecked) code_err(ast, "Table indexes cannot be unchecked");
        if (table_type->default_value) {
            return Texts("Table$get_or_default(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
                         compile_type(table_type->key_type), ", ", compile_type(table_type->value_type), ", ",
                         compile_to_type(env, indexing->index, table_type->key_type), ", ",
                         compile_to_type(env, table_type->default_value, table_type->value_type), ", ",
                         compile_type_info(container_t), ")");
        } else {
            return Texts("Table$get_optional(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
                         compile_type(table_type->key_type), ", ", compile_type(table_type->value_type), ", ",
                         compile_to_type(env, indexing->index, table_type->key_type),
                         ", "
                         "_, ",
                         promote_to_optional(table_type->value_type, Text("(*_)")), ", ",
                         compile_none(table_type->value_type), ", ", compile_type_info(container_t), ")");
        }
    } else if (container_t->tag == TextType) {
        return Texts("Text$cluster(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
                     compile_to_type(env, indexing->index, Type(BigIntType)), ")");
    } else {
        code_err(ast, "Indexing is not supported for type: ", type_to_str(container_t));
    }
}