[go: up one dir, main page]

File: jx_sub.c

package info (click to toggle)
cctools 9.9-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 44,624 kB
  • sloc: ansic: 192,539; python: 20,827; cpp: 20,199; sh: 11,719; perl: 4,106; xml: 3,688; makefile: 1,224
file content (191 lines) | stat: -rw-r--r-- 5,075 bytes parent folder | download
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
Copyright (C) 2021- The University of Notre Dame
This software is distributed under the GNU General Public License.
See the file COPYING for details.
*/

#include "jx_sub.h"
#include "jx_function.h"

#include <assert.h>
#include <string.h>


static struct jx * jx_sub_call( struct jx *func, struct jx *args, struct jx *ctx) {
    assert(func);
    assert(args);
    assert(jx_istype(args, JX_ARRAY));
    assert(jx_istype(func, JX_SYMBOL));

    struct jx *left  = jx_copy(func);
    struct jx *right = jx_function_sub(func->u.symbol_name, args, ctx);
    
    return jx_operator(JX_OP_CALL, left, right);
}

static struct jx * jx_sub_operator( struct jx_operator *o, struct jx *context )
{
    if(!o) return 0;

    struct jx *left  = NULL;
    struct jx *right = NULL;

    if (o->type == JX_OP_CALL) return jx_sub_call(o->left, o->right, context);

    left = jx_sub(o->left, context);
    if (jx_istype(left, JX_ERROR)) {
        return left;
    }

    right = jx_sub(o->right, context);
    if (jx_istype(right, JX_ERROR)) {
        jx_delete(left);
        return right;
    }

    return jx_operator(o->type, left, right);
}

static struct jx_item *jx_sub_comprehension( struct jx *body, struct jx_comprehension *comp, struct jx *context) {
    assert(body);
    assert(comp);

    // for item
    struct jx *value = NULL;

    // for comp
    struct jx *elements = NULL;
    struct jx *condition = NULL;
    struct jx_comprehension *next = NULL;

    elements = jx_sub(comp->elements, context);

    if (jx_istype(elements, JX_ERROR)) {
        return jx_item(elements, NULL);
    }

    // use local var without affecting context, this way we avoid collisions with pairs already in context
    // set variable to null value (base case), so jx_sub() knows to not fill in symbols
    struct jx *ctx = jx_copy(context);
    jx_insert(ctx, jx_string(comp->variable), jx_null());

    if (comp->condition) {
        condition = jx_sub(comp->condition, ctx);

        if (jx_istype(condition, JX_ERROR)) {
            jx_delete(ctx);
            jx_delete(elements);
            return jx_item(condition, NULL);
        }
    }

    if (comp->next) {
        struct jx_item *item = jx_sub_comprehension(body, comp->next, ctx);

        if (!item) {
            jx_delete(ctx);
            jx_delete(elements);
            jx_delete(condition);
            return NULL;
        }

        next = item->comp;
        value = item->value;

        free(item);

    } else {
        // final comp -> do sub on body 
        value = jx_sub(body, ctx);

        if (jx_istype(value, JX_ERROR)) {
            jx_delete(ctx);
            jx_delete(elements);
            jx_delete(condition);
            return jx_item(value, NULL);
        }
    }

    jx_delete(ctx);

    struct jx_item *result = jx_item(value, 0);
    result->comp = jx_comprehension(comp->variable, elements, condition, next);

    return result;
}

static struct jx_pair *jx_sub_pair( struct jx_pair *pair, struct jx *context) {
    if (!pair) return 0;

    return jx_pair(
        jx_sub(pair->key, context),
        jx_sub(pair->value, context),
        jx_sub_pair(pair->next, context));
}

static struct jx_item *jx_sub_item( struct jx_item *item, struct jx *context) {
    if (!item) return NULL;

    struct jx_item *new_item = NULL;

    if (item->comp) {
        new_item = jx_sub_comprehension(item->value, item->comp, context);
        new_item->next = jx_sub_item(item->next, context);
    } else {
        new_item = jx_item(jx_sub(item->value, context), jx_sub_item(item->next, context));
    }

    return new_item;
}

struct jx * jx_sub( struct jx *j, struct jx *context )
{
    struct jx *result = NULL;
    if (!j) return NULL;

    if (context && !jx_istype(context, JX_OBJECT)) {
        return jx_error(jx_string("context must be an object"));
    }

    switch(j->type) {
        case JX_SYMBOL: {
            struct jx *t = jx_lookup(context, j->u.symbol_name);
            if (t) {
                if (jx_istype(t, JX_NULL)) {
                    // for local variables in list comprehensions (don't overwrite)
                    result = jx_copy(j);
                } else {
                    result = jx_sub(t, context);
                }
                break;
            } else {
                return jx_error(jx_format(
                    "on line %d, %s: undefined symbol",
                    j->line,
                    j->u.symbol_name
                ));
            }
        }
        case JX_DOUBLE:
        case JX_BOOLEAN:
        case JX_INTEGER:
        case JX_STRING:
        case JX_ERROR:
        case JX_NULL:
            result = jx_copy(j);
            break;
        case JX_ARRAY:
            result = jx_array(jx_sub_item(j->u.items, context));
            break;
        case JX_OBJECT:
            result = jx_object(jx_sub_pair(j->u.pairs, context));
            break;
        case JX_OPERATOR:
            result = jx_sub_operator(&j->u.oper, context);
            break;
    }

    return result;
}

/*vim: set noexpandtab tabstop=4: */