• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3  *
4  * HDF is dual licensed: you can use it either under the terms of
5  * the GPL, or the BSD license, at your option.
6  * See the LICENSE file in the root of this repository for complete details.
7  */
8 
9 #include <string.h>
10 #include "hcs_compiler.h"
11 #include "hcs_option.h"
12 
13 static int32_t HcsNodeExpand(ParserObject *current);
14 
HcsLookupAstObject(const ParserObject * current,const char * path)15 static ParserObject *HcsLookupAstObject(const ParserObject *current, const char *path)
16 {
17     /* Not absolute path, lookup in peers */
18     if (!strchr(path, '.')) {
19         return HcsAstLookupObjectInPeers(current, path);
20     }
21 
22     /* Absolute path lookup form root and subtree */
23     char *splitPath = strdup(path);
24     if (splitPath == NULL) {
25         HCS_ERROR("oom");
26         return NULL;
27     }
28     char *buf = NULL;
29     char *nodeName = strtok_s(splitPath, ".", &buf);
30 
31     /* path must start with "root" */
32     if (nodeName == NULL || strcmp(nodeName, "root") != 0) {
33         HcsMemFree(splitPath);
34         return NULL;
35     }
36 
37     /* skip root in path */
38     nodeName = strtok_s(NULL, ".", &buf);
39     ParserObject *object = HcsGetParserRoot();
40     while (nodeName != NULL) {
41         object = HcsAstLookupObjectInChildren(object, nodeName);
42         if (object == NULL) {
43             break;
44         }
45         nodeName = strtok_s(NULL, ".", &buf);
46     }
47     HcsMemFree(splitPath);
48 
49     return object;
50 }
51 
HcsExpandNodeRef(ParserObject * object)52 static int32_t HcsExpandNodeRef(ParserObject *object)
53 {
54     ParserObject *refNode = HcsLookupAstObject(object, object->configNode.refNodePath);
55     if (refNode == NULL) {
56         HCS_OBJECT_ERROR(object, "ref node '%s' not exist", object->configNode.refNodePath);
57         return EINVALARG;
58     }
59     if (refNode->objectBase.status != PARSER_OBJ_IDLE) {
60         HCS_OBJECT_ERROR(object, "circular reference '%s'", object->configNode.refNodePath);
61         return EINVALARG;
62     }
63 
64     /* expand target ref or copy */
65     int32_t res = HcsNodeExpand(refNode);
66     if (res) {
67         return res;
68     }
69     ParserObject *child = (ParserObject *)object->objectBase.child;
70     if (child == NULL) {
71         return 0;
72     }
73 
74     res = HcsAstCopySubTree(object, refNode, AST_COPY_SRC_OVER_DST);
75     if (res) {
76         return res;
77     }
78     HcsDeleteParserObjectTree(object);
79     return NOERR;
80 }
81 
HcsExpandNodeCopy(ParserObject * object)82 static int32_t HcsExpandNodeCopy(ParserObject *object)
83 {
84     object->configNode.nodeType = CONFIG_NODE_NOREF;
85     ParserObject *copyNode = HcsLookupAstObject(object, object->configNode.refNodePath);
86     if (copyNode == NULL) {
87         HCS_OBJECT_ERROR(object, "node %s copy node '%s' not exist", object->objectBase.name,
88             object->configNode.refNodePath);
89         return EINVALARG;
90     }
91 
92     /* check copy parent */
93     ParserObjectBase *parent = object->objectBase.parent;
94     while (parent != NULL) {
95         if (parent == &copyNode->objectBase) {
96             HCS_OBJECT_ERROR(object, "Never copy parent node which will make a loop reference");
97             return EINVALARG;
98         }
99         parent = parent->parent;
100     }
101 
102     if (HcsOptShouldGenTextConfig()) {
103         ParserObjectBase *copyChild = copyNode->objectBase.child;
104         while (copyChild != NULL) {
105             if (copyChild->type == PARSEROP_CONFNODE) {
106                 HCS_OBJECT_ERROR(object, "Not allow copy node has child node when output text config, at %s:%u",
107                     copyChild->src, copyChild->lineno);
108                 return EINVALARG;
109             }
110             copyChild = copyChild->next;
111         }
112     }
113 
114     return HcsAstCopySubTree(copyNode, object, AST_COPY_DST_OVER_SRC);
115 }
116 
HcsProcessDelete(ParserObject * current)117 static bool HcsProcessDelete(ParserObject *current)
118 {
119     switch (current->objectBase.type) {
120         case PARSEROP_CONFNODE:
121             if (current->configNode.nodeType == CONFIG_NODE_DELETE) {
122                 HcsDeleteParserObjectTree(current);
123                 return true;
124             }
125             break;
126         case PARSEROP_CONFTERM:
127             if (current->objectBase.child->type == PARSEROP_DELETE) {
128                 HcsDeleteParserObjectTree(current);
129                 return true;
130             }
131             break;
132         default:
133             break;
134     }
135 
136     return false;
137 }
138 
HcsNodeRefAssembling(ParserObject * current)139 static int32_t HcsNodeRefAssembling(ParserObject *current)
140 {
141     ParserObject *refNode =
142         HcsLookupAstObject((ParserObject *)current->objectBase.parent, current->objectBase.stringValue);
143     if (refNode == NULL) {
144         HCS_OBJECT_ERROR(current, "reference invalid node %s", current->objectBase.stringValue);
145         return EINVALARG;
146     }
147     if (refNode->objectBase.type != PARSEROP_CONFNODE) {
148         HCS_OBJECT_ERROR(current, "reference node %s is not node", current->objectBase.stringValue);
149         return EINVALARG;
150     }
151     if (refNode->configNode.nodeType == CONFIG_NODE_REF) {
152         HCS_OBJECT_ERROR(current, "reference node %s referenced another", current->objectBase.stringValue);
153         return EINVALARG;
154     }
155     HcsMemFree(current->objectBase.stringValue);
156     current->objectBase.value = (uint64_t)refNode;
157     return NOERR;
158 }
159 
HcsInheritNodeCompareWithBase(const ParserObject * obj,const ParserObject * base)160 static int32_t HcsInheritNodeCompareWithBase(const ParserObject *obj, const ParserObject *base)
161 {
162     ParserObjectBase *objChild = obj->objectBase.child;
163 
164     while (objChild != NULL) {
165         ParserObject *objInBase = NULL;
166         if (objChild->type == PARSEROP_CONFNODE &&
167             ((ParserObject *)objChild)->configNode.nodeType == CONFIG_NODE_INHERIT) {
168             ParserObject *templateNode =
169                 HcsLookupAstObject((ParserObject *)objChild, ((ParserObject *)objChild)->configNode.refNodePath);
170             if (templateNode == NULL) {
171                 HCS_OBJECT_ERROR(objChild, "node '%s' inherit invalid template", objChild->name);
172                 return EFAIL;
173             }
174             ParserObject *peerTemplate = HcsLookupAstObject((ParserObject *)objChild, templateNode->objectBase.name);
175             if (templateNode != peerTemplate) {
176                 HCS_OBJECT_ERROR(objChild, "term '%s' not in base node", objChild->name);
177                 return EFAIL;
178             }
179             objChild = objChild->next;
180             continue;
181         } else {
182             objInBase = HcsAstLookupObjectInChildren(base, objChild->name);
183         }
184 
185         if (objInBase == NULL) {
186             HCS_OBJECT_ERROR(objChild, "term '%s' not in base node", objChild->name);
187             return EFAIL;
188         }
189         if (objChild->type == PARSEROP_CONFNODE) {
190             return HcsInheritNodeCompareWithBase((ParserObject *)objChild, objInBase);
191         }
192 
193         objChild = objChild->next;
194     }
195     return NOERR;
196 }
197 
HcsAddInstanceToTemplate(ParserObject * instanceNode,ParserObject * template)198 static int32_t HcsAddInstanceToTemplate(ParserObject *instanceNode, ParserObject *template)
199 {
200     TemplateNodeInstance *instance = HcsMemZalloc(sizeof(TemplateNodeInstance));
201     if (instance == NULL) {
202         return EOOM;
203     }
204 
205     instance->nodeObject = (struct ConfigNode *)instanceNode;
206 
207     TemplateNodeInstance *listEnd = template->configNode.subClasses;
208     if (listEnd == NULL) {
209         template->configNode.subClasses = instance;
210     } else {
211         while (listEnd->next != NULL) {
212             listEnd = listEnd->next;
213         }
214 
215         listEnd->next = instance;
216     }
217     instanceNode->configNode.inheritIndex = template->configNode.inheritCount++;
218     return NOERR;
219 }
220 
HcsNodeInheritExpand(ParserObject * obj)221 static int32_t HcsNodeInheritExpand(ParserObject *obj)
222 {
223     ParserObject *base = HcsLookupAstObject(obj, obj->configNode.refNodePath);
224     if (base == NULL || base->objectBase.type != PARSEROP_CONFNODE ||
225         base->configNode.nodeType != CONFIG_NODE_TEMPLATE) {
226         HCS_OBJECT_ERROR(obj, "inherit invalid node : %s", obj->configNode.refNodePath);
227         return EFAIL;
228     }
229 
230     obj->configNode.inheritNode = (struct ConfigNode *)base;
231     int32_t ret = HcsAstCopySubTree(base, obj, AST_COPY_DST_OVER_SRC);
232     if (ret) {
233         return ret;
234     }
235 
236     ret = HcsInheritNodeCompareWithBase(obj, base);
237     if (ret) {
238         return ret;
239     }
240 
241     return HcsAddInstanceToTemplate(obj, base);
242 }
243 
HcsNodeExpand(ParserObject * current)244 static int32_t HcsNodeExpand(ParserObject *current)
245 {
246     if (HcsProcessDelete(current)) {
247         return NOERR;
248     }
249 
250     switch (current->objectBase.type) {
251         case PARSEROP_CONFNODE: {
252             current->objectBase.status = PARSER_OBJ_PROCESSING;
253             int32_t ret = NOERR;
254             if (current->configNode.nodeType == CONFIG_NODE_REF) {
255                 return HcsExpandNodeRef(current);
256             } else if (current->configNode.nodeType == CONFIG_NODE_COPY) {
257                 ret = HcsExpandNodeCopy(current);
258             }
259             current->objectBase.status = PARSER_OBJ_IDLE;
260             return ret;
261         }
262         case PARSEROP_NODEREF:
263             return HcsNodeRefAssembling(current);
264         default:
265             break;
266     }
267 
268     return NOERR;
269 }
270 
HcsRedefineCheck(const ParserObject * object)271 static int32_t HcsRedefineCheck(const ParserObject *object)
272 {
273     if (object->objectBase.child == NULL) {
274         return NOERR;
275     }
276 
277     ParserObject *child = (ParserObject *)object->objectBase.child;
278     while (child != NULL) {
279         if (HcsIsAnonymousObject(object)) {
280             child = (ParserObject *)child->objectBase.next;
281             continue;
282         }
283         ParserObject *next = (ParserObject *)child->objectBase.next;
284         while (next != NULL) {
285             if (!HcsIsAnonymousObject(next) && !strcmp(child->objectBase.name, next->objectBase.name) &&
286                 (child->objectBase.src == next->objectBase.src)) {
287                 HCS_OBJECT_ERROR(next, "'%s' redefined, first define at Line: %u", next->objectBase.name,
288                     child->objectBase.lineno);
289                 return EINVALARG;
290             }
291             next = (ParserObject *)next->objectBase.next;
292         }
293         child = (ParserObject *)child->objectBase.next;
294     }
295 
296     return NOERR;
297 }
298 
HcsMiddleRedefineCheckCallback(ParserObject * current,int32_t walkDepth)299 static int32_t HcsMiddleRedefineCheckCallback(ParserObject *current, int32_t walkDepth)
300 {
301     (void)walkDepth;
302     return HcsRedefineCheck(current);
303 }
304 
HcsMiddleInheritExpandCallback(ParserObject * current,int32_t walkDepth)305 static int32_t HcsMiddleInheritExpandCallback(ParserObject *current, int32_t walkDepth)
306 {
307     (void)walkDepth;
308     if (current->objectBase.type == PARSEROP_CONFNODE && current->configNode.nodeType == CONFIG_NODE_INHERIT) {
309         return HcsNodeInheritExpand(current);
310     }
311 
312     return NOERR;
313 }
314 
HcsMiddleProcessCallback(ParserObject * current,int32_t walkDepth)315 static int32_t HcsMiddleProcessCallback(ParserObject *current, int32_t walkDepth)
316 {
317     (void)walkDepth;
318     return HcsNodeExpand(current);
319 }
320 
HcsApplyDelete(ParserObject * dst,ParserObject * src)321 static bool HcsApplyDelete(ParserObject *dst, ParserObject *src)
322 {
323     if ((dst->objectBase.type == PARSEROP_CONFNODE && dst->configNode.nodeType == CONFIG_NODE_DELETE) ||
324         (dst->objectBase.type == PARSEROP_CONFTERM && dst->objectBase.child->type == PARSEROP_DELETE)) {
325         HCS_OBJECT_WARNING(dst, "target object of delete not in base");
326     }
327 
328     if ((src->objectBase.type == PARSEROP_CONFNODE && src->configNode.nodeType == CONFIG_NODE_DELETE) ||
329         (src->objectBase.type == PARSEROP_CONFTERM && src->objectBase.child->type == PARSEROP_DELETE)) {
330         HcsDeleteParserObjectTree(dst);
331         HcsDeleteParserObjectTree(src);
332         return true;
333     }
334 
335     return false;
336 }
337 
HcsMergeTree(ParserObject * dst,ParserObject * src)338 static int32_t HcsMergeTree(ParserObject *dst, ParserObject *src)
339 {
340     if (strcmp(src->objectBase.name, dst->objectBase.name) != 0) {
341         HCS_OBJECT_ERROR(src, "merge different node to %s:%u", dst->objectBase.src, dst->objectBase.lineno);
342         return EINVALARG;
343     }
344 
345     if (src->objectBase.type != dst->objectBase.type) {
346         HCS_OBJECT_ERROR(src, "conflict type with %s:%u", dst->objectBase.src, dst->objectBase.lineno);
347         return EINVALARG;
348     }
349 
350     if (HcsApplyDelete(dst, src)) {
351         return NOERR;
352     }
353 
354     /* overwrite source info */
355     dst->objectBase.src = src->objectBase.src;
356     dst->objectBase.lineno = src->objectBase.lineno;
357 
358     /* overwrite value of base type  */
359     if (HcsIsStringObject(src)) {
360         HcsMemFree((void *)dst->objectBase.value);
361         dst->objectBase.value = src->objectBase.value;
362         src->objectBase.value = (uint64_t)NULL;
363     } else if (HcsIsNumberObject(src)) {
364         dst->objectBase.value = src->objectBase.value;
365     }
366 
367     /* process sub-tree objects */
368     ParserObject *childSrc = (ParserObject *)src->objectBase.child;
369     int32_t ret = NOERR;
370     while (childSrc != NULL) {
371         ParserObject *childSrcNext = (ParserObject *)childSrc->objectBase.next;
372         ParserObject *childDst = HcsAstLookupObjectInChildren(dst, childSrc->objectBase.name);
373         if (childDst != NULL && childSrc->objectBase.type != childDst->objectBase.type) {
374             HCS_OBJECT_ERROR(childSrc, "overwrite with different type at %s:%u", childDst->objectBase.src,
375                 childDst->objectBase.lineno);
376             return EINVALARG;
377         }
378         if (childDst == NULL) {
379             HcsAstRemoveChildLink(childSrc->objectBase.parent, (ParserObjectBase *)childSrc);
380             HcsAstAddChild(dst, childSrc);
381         } else if (childDst->objectBase.type == PARSEROP_ARRAY) {
382             ret = HcsAstCopyArray(childSrc, childDst);
383             break;
384         } else {
385             ret = HcsMergeTree(childDst, childSrc);
386             if (ret) {
387                 break;
388             }
389         }
390         childSrc = childSrcNext;
391     }
392 
393     return ret;
394 }
395 
HcsOrderForest(ParserObject * root)396 static void HcsOrderForest(ParserObject *root)
397 {
398     if (root->objectBase.child == NULL) {
399         return;
400     }
401 
402     ParserObjectBase *childStart = root->objectBase.child;
403     ParserObjectBase *pre = childStart;
404     ParserObjectBase *next = childStart->next;
405     while (next != NULL) {
406         ParserObjectBase *tmp = next->next;
407         next->next = pre;
408         pre = next;
409         next = tmp;
410     }
411 
412     childStart->next = NULL;
413     root->objectBase.child = pre;
414 }
415 
HcsMiddleMerge(ParserObject ** mergedRoot)416 static int32_t HcsMiddleMerge(ParserObject **mergedRoot)
417 {
418     ParserObject *root = HcsGetParserRoot();
419     HcsOrderForest(root);
420 
421     ParserObject *peer = (ParserObject *)root->objectBase.child;
422     while (peer->objectBase.next != NULL) {
423         ParserObject *next = (ParserObject *)peer->objectBase.next;
424         int32_t res = HcsMergeTree(peer, next);
425         if (res) {
426             return res;
427         }
428         HcsDeleteParserObjectTree(next);
429     }
430     HcsAstRemoveChildLink(peer->objectBase.parent, &peer->objectBase);
431     HcsSetParserRoot(peer);
432     *mergedRoot = peer;
433     return NOERR;
434 }
435 
HcsDoOptimize(void)436 int32_t HcsDoOptimize(void)
437 {
438     ParserObject *root = HcsGetParserRoot();
439     if (root == NULL) {
440         HCS_ERROR("parser return empty ast");
441         return EINVALARG;
442     }
443 
444     /* redefine check */
445     int32_t ret = HcsWalkAst(root, AST_WALK_BACKEND, NULL, HcsMiddleRedefineCheckCallback);
446     if (ret) {
447         return ret;
448     }
449 
450     /* merge multi file objects */
451     ret = HcsMiddleMerge(&root);
452     if (ret) {
453         return ret;
454     }
455 
456     const char *moduleName = HcsGetModuleName();
457     if (moduleName == NULL) {
458         return EINVALARG;
459     }
460     HCS_DEBUG("compile module : %s", moduleName);
461     /* expend node ref and node copy */
462     ret = HcsWalkAst(root, AST_WALK_BACKEND, NULL, HcsMiddleProcessCallback);
463     if (ret) {
464         return ret;
465     }
466 
467     ret = HcsWalkAst(root, AST_WALK_FORWARD, HcsMiddleInheritExpandCallback, NULL);
468     if (ret) {
469         return ret;
470     }
471 
472     if (HcsVerbosePrint()) {
473         HcsDumpAst("Optimized");
474     }
475     return ret;
476 }