save
[protos/libecoli.git] / lib / ecoli_parsed.c
1 /*
2  * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <errno.h>
33
34 #include <ecoli_malloc.h>
35 #include <ecoli_strvec.h>
36 #include <ecoli_keyval.h>
37 #include <ecoli_log.h>
38 #include <ecoli_node.h>
39 #include <ecoli_parsed.h>
40
41 int ec_node_parse_child(struct ec_node *node, struct ec_parsed *state,
42                         const struct ec_strvec *strvec)
43 {
44         struct ec_strvec *match_strvec;
45         struct ec_parsed *child;
46         int ret;
47
48         assert(state != NULL);
49
50         /* build the node if required */
51         if (node->type->build != NULL) {
52                 if ((node->flags & EC_NODE_F_BUILT) == 0) {
53                         ret = node->type->build(node);
54                         if (ret < 0)
55                                 return ret;
56                 }
57         }
58         node->flags |= EC_NODE_F_BUILT;
59
60         if (node->type->parse == NULL)
61                 return -ENOTSUP;
62
63         child = ec_parsed();
64         if (child == NULL)
65                 return -ENOMEM;
66
67         child->node = node;
68         ec_parsed_add_child(state, child);
69         ret = node->type->parse(node, child, strvec);
70         if (ret == EC_PARSED_NOMATCH) {
71                 ec_parsed_del_child(state, child);
72                 assert(TAILQ_EMPTY(&child->children));
73                 ec_parsed_free(child);
74                 return ret;
75         } else if (ret < 0) {
76                 return ret;
77         }
78
79         match_strvec = ec_strvec_ndup(strvec, 0, ret);
80         if (match_strvec == NULL)
81                 return -ENOMEM;
82
83         child->strvec = match_strvec;
84
85         return ret;
86 }
87
88 struct ec_parsed *ec_node_parse_strvec(struct ec_node *node,
89                                 const struct ec_strvec *strvec)
90 {
91         struct ec_parsed *parsed = ec_parsed();
92         struct ec_parsed *child_parsed;
93         int ret;
94
95         if (parsed == NULL)
96                 return NULL;
97
98         ret = ec_node_parse_child(node, parsed, strvec);
99         if (ret < 0 && ret != EC_PARSED_NOMATCH) {
100                 ec_parsed_free(parsed);
101                 parsed = NULL;
102         } else if (ret != EC_PARSED_NOMATCH) {
103                 /* remove dummy root node */
104                 child_parsed = ec_parsed_get_last_child(parsed);
105                 ec_parsed_del_child(parsed, child_parsed);
106                 ec_parsed_free(parsed);
107                 parsed = child_parsed;
108         }
109
110         return parsed;
111 }
112
113 struct ec_parsed *ec_node_parse(struct ec_node *node, const char *str)
114 {
115         struct ec_strvec *strvec = NULL;
116         struct ec_parsed *parsed = NULL;
117
118         errno = ENOMEM;
119         strvec = ec_strvec();
120         if (strvec == NULL)
121                 goto fail;
122
123         if (ec_strvec_add(strvec, str) < 0)
124                 goto fail;
125
126         parsed = ec_node_parse_strvec(node, strvec);
127         if (parsed == NULL)
128                 goto fail;
129
130         ec_strvec_free(strvec);
131         return parsed;
132
133  fail:
134         ec_strvec_free(strvec);
135         ec_parsed_free(parsed);
136         return NULL;
137 }
138
139 struct ec_parsed *ec_parsed(void)
140 {
141         struct ec_parsed *parsed = NULL;
142
143         parsed = ec_calloc(1, sizeof(*parsed));
144         if (parsed == NULL)
145                 goto fail;
146
147         TAILQ_INIT(&parsed->children);
148
149         return parsed;
150
151  fail:
152         return NULL;
153 }
154
155 void ec_parsed_free_children(struct ec_parsed *parsed)
156 {
157         struct ec_parsed *child;
158
159         if (parsed == NULL)
160                 return;
161
162         while (!TAILQ_EMPTY(&parsed->children)) {
163                 child = TAILQ_FIRST(&parsed->children);
164                 TAILQ_REMOVE(&parsed->children, child, next);
165                 ec_parsed_free(child);
166         }
167 }
168
169 void ec_parsed_free(struct ec_parsed *parsed)
170 {
171         if (parsed == NULL)
172                 return;
173
174         ec_parsed_free_children(parsed);
175         ec_strvec_free(parsed->strvec);
176         ec_free(parsed);
177 }
178
179 static void __ec_parsed_dump(FILE *out,
180         const struct ec_parsed *parsed, size_t indent)
181 {
182         struct ec_parsed *child;
183         const struct ec_strvec *vec;
184         size_t i;
185         const char *id = "none", *typename = "none";
186
187         if (parsed->node != NULL) {
188                 if (parsed->node->id != NULL)
189                         id = parsed->node->id;
190                 typename = parsed->node->type->name;
191         }
192
193         /* XXX enhance */
194         for (i = 0; i < indent; i++) {
195                 if (i % 2)
196                         fprintf(out, " ");
197                 else
198                         fprintf(out, "|");
199         }
200
201         fprintf(out, "node_type=%s id=%s vec=", typename, id);
202         vec = ec_parsed_strvec(parsed);
203         if (vec == NULL) {
204                 fprintf(out, "none\n");
205         } else {
206                 for (i = 0; i < ec_strvec_len(vec); i++)
207                         fprintf(out, "%s<%s>",
208                                 i == 0 ? "" : ",",
209                                 ec_strvec_val(vec, i));
210                 // XXX
211                 if (!strcmp(typename, "int") || !strcmp(typename, "str"))
212                         fprintf(out, "] <<<<<\n");
213                 else
214                         fprintf(out, "]\n");
215         }
216
217         TAILQ_FOREACH(child, &parsed->children, next)
218                 __ec_parsed_dump(out, child, indent + 2);
219 }
220
221 void ec_parsed_dump(FILE *out, const struct ec_parsed *parsed)
222 {
223         fprintf(out, "------------------- parsed dump:\n"); //XXX
224
225         if (parsed == NULL) {
226                 fprintf(out, "parsed is NULL, error in parse\n");
227                 return;
228         }
229         if (!ec_parsed_matches(parsed)) {
230                 fprintf(out, "no match\n");
231                 return;
232         }
233
234         __ec_parsed_dump(out, parsed, 0);
235 }
236
237 void ec_parsed_add_child(struct ec_parsed *parsed,
238         struct ec_parsed *child)
239 {
240         TAILQ_INSERT_TAIL(&parsed->children, child, next);
241         child->parent = parsed;
242 }
243
244 void ec_parsed_del_child(struct ec_parsed *parsed,
245         struct ec_parsed *child)
246 {
247         TAILQ_REMOVE(&parsed->children, child, next);
248         child->parent = NULL;
249 }
250
251 struct ec_parsed *
252 ec_parsed_get_last_child(struct ec_parsed *parsed)
253 {
254         return TAILQ_LAST(&parsed->children, ec_parsed_list);
255 }
256
257 void ec_parsed_del_last_child(struct ec_parsed *parsed)
258 {
259         struct ec_parsed *child;
260
261         child = ec_parsed_get_last_child(parsed);
262         ec_parsed_del_child(parsed, child);
263         ec_parsed_free(child);
264 }
265
266 struct ec_parsed *ec_parsed_get_root(struct ec_parsed *parsed)
267 {
268         if (parsed == NULL)
269                 return NULL;
270
271         while (parsed->parent != NULL)
272                 parsed = parsed->parent;
273
274         return parsed;
275 }
276
277 struct ec_parsed *ec_parsed_get_parent(struct ec_parsed *parsed)
278 {
279         if (parsed == NULL)
280                 return NULL;
281
282         return parsed->parent;
283 }
284
285 struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed,
286         const char *id)
287 {
288         struct ec_parsed *child, *ret;
289
290         if (parsed == NULL)
291                 return NULL;
292
293         if (parsed->node != NULL &&
294                         parsed->node->id != NULL &&
295                         !strcmp(parsed->node->id, id))
296                 return parsed;
297
298         TAILQ_FOREACH(child, &parsed->children, next) {
299                 ret = ec_parsed_find_first(child, id);
300                 if (ret != NULL)
301                         return ret;
302         }
303
304         return NULL;
305 }
306
307 const struct ec_strvec *ec_parsed_strvec(const struct ec_parsed *parsed)
308 {
309         if (parsed == NULL || parsed->strvec == NULL)
310                 return NULL;
311
312         return parsed->strvec;
313 }
314
315 /* number of parsed strings in the vector */
316 size_t ec_parsed_len(const struct ec_parsed *parsed)
317 {
318         if (parsed == NULL || parsed->strvec == NULL)
319                 return 0;
320
321         return ec_strvec_len(parsed->strvec);
322 }
323
324 size_t ec_parsed_matches(const struct ec_parsed *parsed)
325 {
326         if (parsed == NULL)
327                 return 0;
328
329         if (parsed->node == NULL && TAILQ_EMPTY(&parsed->children)) // XXX both needed?
330                 return 0;
331
332         return 1;
333 }