aboutsummaryrefslogtreecommitdiff
path: root/src_c/env.c
blob: 13999d5cecdde5a39703023e881431aa8b8768f8 (plain) (blame)
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
74
75
76
77
78
79
80
81
82
83
84
85
86
#include "env.h"
#include "ctx.h"
#include "eval.h"


static void init_result(lsp_env_t *e) {
    e->result.is_value = true;
    e->result.ctx = e->m->nil;
    e->result.value = e->m->nil;
}


static void release_result(lsp_env_t *e) {
    lsp_mem_dec_ref(e->m, e->result.ctx);
    lsp_mem_dec_ref(e->m, e->result.value);

    init_result(e);
}


void lsp_env_init(lsp_env_t *e, lsp_mem_t *m, lsp_in_stream_t *in,
                  lsp_out_stream_t *out) {
    e->m = m;
    e->in = in;
    e->out = out;

    init_result(e);
}


lsp_status_t lsp_env_set_result_value(lsp_env_t *e, lsp_addr_t value) {
    release_result(e);

    lsp_status_t status = lsp_mem_inc_ref(e->m, value);
    if (status != LSP_SUCCESS)
        return status;

    e->result.is_value = true;
    e->result.value = value;
    return LSP_SUCCESS;
}


lsp_status_t lsp_env_set_result_eval(lsp_env_t *e, lsp_addr_t ctx,
                                     lsp_addr_t value) {
    release_result(e);

    lsp_status_t status = lsp_mem_inc_ref(e->m, ctx);
    if (status != LSP_SUCCESS)
        return status;

    status = lsp_mem_inc_ref(e->m, value);
    if (status != LSP_SUCCESS) {
        lsp_mem_dec_ref(e->m, ctx);
        return status;
    }

    e->result.is_value = false;
    e->result.ctx = ctx;
    e->result.value = value;
    return LSP_SUCCESS;
}


lsp_status_t lsp_env_resolve(lsp_env_t *e, lsp_addr_t ctx, lsp_addr_t value,
                             lsp_addr_t *result) {
    lsp_status_t status = lsp_env_set_result_eval(e, ctx, value);
    if (status != LSP_SUCCESS)
        return status;

    while (!e->result.is_value) {
        lsp_addr_t eval_ctx = e->result.ctx;
        lsp_addr_t eval_value = e->result.value;
        init_result(e);

        status = lsp_eval(e, eval_ctx, eval_value);
        lsp_mem_dec_ref(e->m, eval_ctx);
        lsp_mem_dec_ref(e->m, eval_value);
        if (status != LSP_SUCCESS)
            return status;
    }

    *result = e->result.value;
    init_result(e);
    return LSP_SUCCESS;
}