38f42b8da2f3483e695186e15a905ffc06ae1f06
[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         ec_parsed_add_child(state, child);
68         ret = node->type->parse(node, child, strvec);
69         if (ret == EC_PARSED_NOMATCH) {
70                 ec_parsed_del_child(state, child);
71                 assert(TAILQ_EMPTY(&child->children));
72                 ec_parsed_free(child);
73                 return ret;
74         } else if (ret < 0) {
75                 return ret;
76         }
77
78         match_strvec = ec_strvec_ndup(strvec, 0, ret);
79         if (match_strvec == NULL)
80                 return -ENOMEM;
81
82         child->node = node;
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         for (i = 0; i < ec_strvec_len(vec); i++)
204                 fprintf(out, "%s<%s>",
205                         i == 0 ? "" : ",",
206                         ec_strvec_val(vec, i));
207         // XXX
208         if (!strcmp(typename, "int") || !strcmp(typename, "str"))
209                 fprintf(out, "] <<<<<\n");
210         else
211                 fprintf(out, "]\n");
212
213         TAILQ_FOREACH(child, &parsed->children, next)
214                 __ec_parsed_dump(out, child, indent + 2);
215 }
216
217 void ec_parsed_dump(FILE *out, const struct ec_parsed *parsed)
218 {
219         fprintf(out, "------------------- parsed dump:\n"); //XXX
220
221         if (parsed == NULL) {
222                 fprintf(out, "parsed is NULL, error in parse\n");
223                 return;
224         }
225         if (!ec_parsed_matches(parsed)) {
226                 fprintf(out, "no match\n");
227                 return;
228         }
229
230         __ec_parsed_dump(out, parsed, 0);
231 }
232
233 void ec_parsed_add_child(struct ec_parsed *parsed,
234         struct ec_parsed *child)
235 {
236         TAILQ_INSERT_TAIL(&parsed->children, child, next);
237         child->parent = parsed;
238 }
239
240 void ec_parsed_del_child(struct ec_parsed *parsed,
241         struct ec_parsed *child)
242 {
243         TAILQ_REMOVE(&parsed->children, child, next);
244         child->parent = NULL;
245 }
246
247 struct ec_parsed *
248 ec_parsed_get_last_child(struct ec_parsed *parsed)
249 {
250         return TAILQ_LAST(&parsed->children, ec_parsed_list);
251 }
252
253 struct ec_parsed *ec_parsed_get_root(struct ec_parsed *parsed)
254 {
255         if (parsed == NULL)
256                 return NULL;
257
258         while (parsed->parent != NULL)
259                 parsed = parsed->parent;
260
261         return parsed;
262 }
263
264 struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed,
265         const char *id)
266 {
267         struct ec_parsed *child, *ret;
268
269         if (parsed == NULL)
270                 return NULL;
271
272         if (parsed->node != NULL &&
273                         parsed->node->id != NULL &&
274                         !strcmp(parsed->node->id, id))
275                 return parsed;
276
277         TAILQ_FOREACH(child, &parsed->children, next) {
278                 ret = ec_parsed_find_first(child, id);
279                 if (ret != NULL)
280                         return ret;
281         }
282
283         return NULL;
284 }
285
286 const struct ec_strvec *ec_parsed_strvec(const struct ec_parsed *parsed)
287 {
288         if (parsed == NULL || parsed->strvec == NULL)
289                 return NULL;
290
291         return parsed->strvec;
292 }
293
294 /* number of parsed strings in the vector */
295 size_t ec_parsed_len(const struct ec_parsed *parsed)
296 {
297         if (parsed == NULL || parsed->strvec == NULL)
298                 return 0;
299
300         return ec_strvec_len(parsed->strvec);
301 }
302
303 size_t ec_parsed_matches(const struct ec_parsed *parsed)
304 {
305         if (parsed == NULL)
306                 return 0;
307
308         if (parsed->node == NULL && TAILQ_EMPTY(&parsed->children)) // XXX both needed?
309                 return 0;
310
311         return 1;
312 }