-
Notifications
You must be signed in to change notification settings - Fork 0
/
sunlark_dictionaries.c
268 lines (239 loc) · 8.52 KB
/
sunlark_dictionaries.c
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "log.h"
#include "utarray.h"
#include "utstring.h"
#include "s7.h"
#include "sunlark_dictionaries.h"
/*
4: TK_Dict_Expr[105] @11:12
5: TK_LBRACE[48] @11:12
5: TK_Dict_Entry_List[104] @12:8
6: TK_Dict_Entry[103] @12:8
7: TK_STRING[79] @12:8 "ckey1"
7: TK_COLON[14] @12:15
7: TK_STRING[79] @12:17 "cval1"
6: TK_COMMA[15] @12:24
6: TK_Dict_Entry[103] @13:8
7: TK_STRING[79] @13:8 "ckey2"
7: TK_COLON[14] @13:15
7: TK_INT[79] @13:17 7
6: TK_COMMA[15] @13:24
...etc...
5: TK_RBRACE[68] @15:4
*/
s7_pointer sunlark_dict_expr_dispatcher(s7_scheme *s7,
struct node_s *dict,
s7_pointer path_args)
{
#ifdef DEBUG_TRACE
log_debug("sunlark_dict_expr_dispatcher %d %s: %s",
dict->tid, TIDNAME(dict),
s7_object_to_c_string(s7, path_args));
#endif
assert(dict->tid == TK_Dict_Expr);
int arg_ct = s7_list_length(s7, path_args);
/* path len min: 1? */
/* path len max: 4? e.g. for vec val: "akey" :value :0 :$ */
int path_len = s7_list_length(s7, path_args);
s7_pointer idx = s7_car(path_args);
if (s7_is_integer(idx)) {
log_error("Invalid index: %d - did you mean :%d ?",
s7_integer(idx), s7_integer(idx));
errno = EINVALID_INT_INDEX;
return NULL;
}
if (s7_is_string(idx)) {
/* string key lookup */
errno = 0;
struct node_s *entry;
entry = sealark_dict_entry_for_string_key(dict, s7_string(idx));
if (entry == NULL)
return handle_errno(s7, errno, path_args);
assert(entry->tid == TK_Dict_Entry);
if (path_len == 0) {
log_error("Unexpected: empty path args");
errno = EUNEXPECTED_STATE;
return NULL;
}
if (path_len == 1) { /* e.g. ("akey") */
return sunlark_new_node(s7, entry);
}
/* path_len must be > 1 */
s7_pointer arg2 = s7_cadr(path_args);
struct node_s *val;
if (arg2 == KW(key)) {
if (path_len > 2) {
log_error("Arg :key must come last in this context, got %s",
s7_object_to_c_string(s7, path_args));
errno = ETOO_MANY_ARGS;
return NULL;
}
struct node_s *nd = utarray_eltptr(entry->subnodes, 0);
return sunlark_new_node(s7, nd);
} else {
if (arg2 == KW(value) || arg2 == s7_make_keyword(s7, "$")) {
val = utarray_eltptr(entry->subnodes, 2);
} else {
log_error("Second arg must be :key or :value, got: %s",
s7_object_to_c_string(s7, arg2));
errno = EINVALID_ARG;
return NULL;
}
}
if (path_len == 2) return sunlark_new_node(s7, val);
if (path_len == 3) { /* e.g. ("akey" :value :0) */
assert(val->tid = TK_List_Expr);
s7_pointer arg3 = s7_caddr(path_args);
if (s7_is_string(arg3)) {
} else {
errno = 0;
int idx = sunlark_is_nbr_kw(s7, arg3);
if (errno != 0) {
errno = EINVALID_ARG;
return NULL;
} else {
struct node_s *item =
sealark_vector_item_for_int(val, idx);
if (item)
return sunlark_new_node(s7, item);
else
return NULL;
}
}
}
errno = ETOO_MANY_ARGS;
return NULL;
}
/* not string, not int */
int i = sunlark_kwindex_to_int(s7, idx);
if (errno == 0) {// we got an int
/* log_debug("indexing at %d", i); */
errno = 0;
struct node_s *dict_entry
= sealark_dict_entry_for_int(dict, i);
if (arg_ct == 1) {
if (dict_entry)
return sunlark_new_node(s7, dict_entry);
else
return NULL;
}
s7_pointer entry_ref = s7_cadr(path_args);
if (entry_ref == KW(key)) {
struct node_s *k = utarray_eltptr(dict_entry->subnodes, 0);
return sunlark_new_node(s7, k);
}
if (entry_ref == KW(value) || entry_ref == s7_make_keyword(s7,"$")) {
struct node_s *v = utarray_eltptr(dict_entry->subnodes, 2);
return sunlark_new_node(s7, v);
}
} else {
if (idx == KW(length)) {
int l = sealark_dict_expr_length(dict);
return s7_make_integer(s7, l);
} else {
s7_pointer result
= sunlark_common_property_lookup(s7, dict, idx);
if (result) {
errno = 0;
return result;
} else
return handle_errno(s7, errno, path_args);
}
}
return NULL;
}
/* **************************************************************** */
/* struct node_s * */
s7_pointer sunlark_dict_entry_dispatcher(s7_scheme *s7,
struct node_s *dentry,
s7_pointer path_args)
{
#ifdef DEBUG_TRACE
log_debug("sunlark_dict_entry_dispatcher %d %s: %s",
dentry->tid, TIDNAME(dentry),
s7_object_to_c_string(s7, path_args));
#endif
assert(dentry->tid == TK_Dict_Entry);
int path_len = s7_list_length(s7, path_args);
s7_pointer op = s7_car(path_args);
if (op == KW(key)) {
struct node_s *r = utarray_eltptr(dentry->subnodes, 0);
return sunlark_new_node(s7, r);
}
if (op == KW(value) || op == s7_make_keyword(s7, "$")) {
struct node_s *v = utarray_eltptr(dentry->subnodes, 2);
if (path_len == 1)
return sunlark_new_node(s7, v);
else {
/* next arg must be an index e.g. :0 */
if (path_len == 2) {
s7_pointer idx = s7_cadr(path_args);
switch(v->tid) {
case TK_List_Expr:
return sunlark_vector_dispatcher(s7, v,
s7_list(s7,1,idx));
break;
case TK_Dict_Expr:
/* should not happen for BUILD files */
log_error("Found dict value in dict");
break;
default:
log_error("Trying to index a non-list: %d %s",
v->tid, TIDNAME(v));
errno = EINVALID_ARG;
return NULL;
}
} else {
log_error("Too many args: %s",
s7_object_to_c_string(s7, path_args));
errno = ETOO_MANY_ARGS;
return NULL;
}
}
}
/* log_error("Invalid arg for dict-entry: %s", */
/* s7_object_to_c_string(s7, path_args)); */
errno = 0; //EINVALID_ARG;
return NULL;
}
/* **************************************************************** */
struct node_s *sunlark_mutate_dict_expr(s7_scheme *s7,
struct node_s *dict_expr,
s7_pointer lval,
s7_pointer update_val)
{
#ifdef DEBUG_TRACE
log_debug("sunlark_mutate_dict_expr");
log_debug("lval %s; update: %s",
s7_object_to_c_string(s7, lval),
s7_object_to_c_string(s7, update_val));
#endif
assert(dict_expr->tid == TK_Dict_Expr);
if (update_val == KW(null)) {
int idx = sunlark_kwindex_to_int(s7, lval);
if (errno == 0) // we got an int
return sealark_dexpr_rm_entry_for_int(dict_expr, idx);
else {
if (s7_is_string(lval)) {
return sealark_dexpr_rm_entry_for_string(dict_expr,
s7_string(lval));
}
if (s7_is_symbol(lval)) {
return sealark_dexpr_rm_entry_for_string(dict_expr,
s7_symbol_name(lval));
}
log_error("Invalid dict index: %s",
s7_object_to_c_string(s7, lval));
errno = EINVALID_INDEX;
return NULL;
}
}
log_debug("FIXME");
return dict_expr;
}