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 == ©Node->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 }