aboutsummaryrefslogtreecommitdiff
path: root/src/compile/pointers.c
blob: 113483308ac3689eff5eb65b556c997d9302a9e6 (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
// This file defines how to compile pointers and allocated memory

#include <gc.h>
#include <glob.h>
#include <gmp.h>
#include <uninorm.h>

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

public
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_text(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) val = Texts("TABLE_COPY(", val, ")");

    return val;
}

public
Text_t compile_typed_allocation(env_t *env, ast_t *ast, type_t *pointer_type) {
    // TODO: for constructors, do new(T, ...) instead of heap((T){...})
    type_t *pointed = Match(pointer_type, PointerType)->pointed;
    switch (ast->tag) {
    case HeapAllocate: {
        return Texts("heap(", compile_to_type(env, Match(ast, HeapAllocate)->value, pointed), ")");
    }
    case StackReference: {
        ast_t *subject = Match(ast, StackReference)->value;
        if (can_be_mutated(env, subject) && type_eq(pointed, get_type(env, subject)))
            return Texts("(&", compile_lvalue(env, subject), ")");
        else return Texts("stack(", compile_to_type(env, subject, pointed), ")");
    }
    default: code_err(ast, "Not an allocation!");
    }
    return EMPTY_TEXT;
}