aboutsummaryrefslogtreecommitdiff
path: root/src/compile/pointer.c
blob: 50c267b64f3df3703e5c627c78081d96ca371677 (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
// Compilation logic
#include <gc.h>
#include <glob.h>
#include <gmp.h>
#include <uninorm.h>

#include "../ast.h"
#include "../compile.h"
#include "../config.h"
#include "../environment.h"
#include "../stdlib/text.h"
#include "../typecheck.h"
#include "list.h"

Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref) {
    Text_t val = compile(env, ast);
    type_t *t = get_type(env, ast);
    int64_t depth = 0;
    for (type_t *tt = t; tt->tag == PointerType; tt = Match(tt, PointerType)->pointed)
        ++depth;

    // Passing a literal value won't trigger an incref, because it's ephemeral,
    // e.g. [10, 20].reversed()
    if (t->tag != PointerType && needs_incref && !can_be_mutated(env, ast)) needs_incref = false;

    while (depth != target_depth) {
        if (depth < target_depth) {
            if (ast->tag == Var && target_depth == 1) val = Texts("(&", val, ")");
            else code_err(ast, "This should be a pointer, not ", type_to_str(get_type(env, ast)));
            t = Type(PointerType, .pointed = t, .is_stack = true);
            ++depth;
        } else {
            DeclareMatch(ptr, t, PointerType);
            val = Texts("*(", val, ")");
            t = ptr->pointed;
            --depth;
        }
    }

    while (t->tag == PointerType) {
        DeclareMatch(ptr, t, PointerType);
        t = ptr->pointed;
    }

    if (needs_incref && t->tag == ListType) val = Texts("LIST_COPY(", val, ")");
    else if (needs_incref && (t->tag == TableType || t->tag == SetType)) val = Texts("TABLE_COPY(", val, ")");

    return val;
}