1 /*
2  * Copyright (c) 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 <set>
10 
11 #include "file.h"
12 #include "logger.h"
13 #include "opcode.h"
14 #include "text_gen.h"
15 
16 using namespace OHOS::Hardware;
17 
18 constexpr static const char *FILE_HEAD_COMMENT =
19     "/*\n"
20     " * This is an automatically generated HDF config file. Do not modify it manually.\n"
21     " */\n\n";
22 
TextGen(std::shared_ptr<Ast> ast)23 TextGen::TextGen(std::shared_ptr<Ast> ast) : Generator(ast) {}
24 
Output()25 bool TextGen::Output()
26 {
27     if (!Initialize() || !DuplicateNodeNameCheck()) {
28         return false;
29     }
30 
31     auto ret = HeaderOutput();
32     if (ret) {
33         ret = ImplOutput();
34     }
35 
36     if (!ret && (ofs_.is_open() && !ofs_.good())) {
37         Logger().Error() << "failed to write file:" << outputFileName_;
38     }
39 
40     return ret;
41 }
42 
Initialize()43 bool TextGen::Initialize()
44 {
45     auto opt = Option::Instance();
46     prefix_ = opt.GetSymbolPrefix();
47     if (prefix_.empty()) {
48         prefix_ = "HdfConfig";
49     }
50 
51     prefix_ = ToLowerCamelString(prefix_);
52 
53     auto moduleTerm = ast_->GetAstRoot()->Lookup("module", PARSEROP_CONFTERM);
54     if (moduleTerm == nullptr) {
55         return false; // never hit
56     }
57 
58     moduleName_ = ToUpperCamelString(moduleTerm->Child()->StringValue());
59     rootVariableName_ = "g_" + prefix_ + moduleName_ + "ModuleRoot";
60     return true;
61 }
62 
HeaderOutput()63 bool TextGen::HeaderOutput()
64 {
65     if (!InitOutput(".h")) {
66         return false;
67     }
68     ofs_ << FILE_HEAD_COMMENT;
69 
70     std::string headerMacro = GetHeaderProtectMacro(outputFileName_);
71     ofs_ << "#ifndef " << headerMacro << "\n";
72     ofs_ << "#define " << headerMacro << "\n\n";
73     ofs_ << "#include <stdint.h>\n\n";
74 
75     if (!HeaderOutputTraversal()) {
76         return false;
77     }
78 
79     ofs_ << "\n#endif // " << headerMacro << '\n';
80     return ofs_.good();
81 }
82 
HeaderOutputTraversal()83 bool TextGen::HeaderOutputTraversal()
84 {
85     auto ret = ast_->WalkBackward([this](const std::shared_ptr<AstObject> &current, int32_t) -> uint32_t {
86         if (!current->IsNode()) {
87             return NOERR;
88         }
89         auto node = ConfigNode::CastFrom(current);
90         if (node->GetNodeType() == NODE_INHERIT) {
91             return NOERR;
92         }
93 
94         return GenNodeDefinition(current);
95     });
96     if (!ret) {
97         return false;
98     }
99 
100     ofs_ << "const struct " << ToUpperCamelString(prefix_) << moduleName_ << "Root* HdfGet" << moduleName_
101          << "ModuleConfigRoot(void);\n";
102     return ofs_.good();
103 }
104 
ImplOutput()105 bool TextGen::ImplOutput()
106 {
107     if (!InitOutput(".c")) {
108         return false;
109     }
110     symMap.clear();
111     ofs_ << FILE_HEAD_COMMENT;
112     ofs_ << "#include \"" << outputNameBase_ << ".h\"\n\n";
113 
114     bool ret = OutputTemplateImpl();
115     if (ret) {
116         ret = OutputImplGlobalVariables();
117     }
118 
119     if (!ret) {
120         return ret;
121     }
122 
123     ofs_ << "\nconst struct " << ToUpperCamelString(prefix_) << moduleName_ << "Root* HdfGet" << moduleName_
124          << "ModuleConfigRoot(void)\n"
125          << "{\n"
126          << Indent() << "return &" << rootVariableName_ << ";\n"
127          << "}\n";
128 
129     return ofs_.good();
130 }
131 
ToUpperCamelString(const std::string & str)132 std::string TextGen::ToUpperCamelString(const std::string &str)
133 {
134     if (str.empty()) {
135         return str;
136     }
137     auto out = ToCamelString(str);
138     out[0] = static_cast<char>(toupper(out[0]));
139 
140     return out;
141 }
142 
ToLowerCamelString(const std::string & str)143 std::string TextGen::ToLowerCamelString(const std::string &str)
144 {
145     if (str.empty()) {
146         return str;
147     }
148     auto out = ToCamelString(str);
149     out[0] = static_cast<char>(tolower(out[0]));
150 
151     return out;
152 }
153 
ToCamelString(const std::string & str)154 std::string TextGen::ToCamelString(const std::string &str)
155 {
156     if (str.empty()) {
157         return str;
158     }
159 
160     if (str.find('_') == std::string::npos) {
161         return str;
162     }
163 
164     std::string out;
165     char cb = '\0';
166     constexpr char underLine = '_';
167     for (auto c : str) {
168         if (c == '_') {
169             cb = c;
170             continue;
171         }
172 
173         if (cb == underLine) {
174             out.push_back(static_cast<char>(toupper(c)));
175         } else {
176             out.push_back(c);
177         }
178 
179         cb = c;
180     }
181 
182     return out;
183 }
184 
InitOutput(const std::string & fileSuffix)185 bool TextGen::InitOutput(const std::string &fileSuffix)
186 {
187     ofs_.close();
188     outputFileName_ = Option::Instance().GetOutputName();
189     if (outputFileName_.empty()) {
190         outputFileName_ = Option::Instance().GetSourceNameBase();
191     }
192     outputFileName_ = Util::File::StripSuffix(outputFileName_).append(fileSuffix);
193     outputNameBase_ = Util::File::FileNameBase(outputFileName_);
194 
195     ofs_.open(outputFileName_, std::ostream::out | std::ostream::binary);
196     if (!ofs_.is_open()) {
197         Logger().Error() << "failed to open output file: " << outputFileName_;
198         return false;
199     }
200 
201     return true;
202 }
203 
ToUpperString(std::string & str)204 const std::string &TextGen::ToUpperString(std::string &str)
205 {
206     for (char &i : str) {
207         i = static_cast<char>(toupper(i));
208     }
209 
210     return str;
211 }
212 
GetHeaderProtectMacro(const std::string & headerFileName)213 std::string TextGen::GetHeaderProtectMacro(const std::string &headerFileName)
214 {
215     (void)headerFileName;
216     return std::string().append("HCS_CONFIG_").append(ToUpperString(outputNameBase_)).append("_HEADER_H");
217 }
218 
GenNodeDefinition(const std::shared_ptr<AstObject> & node)219 uint32_t TextGen::GenNodeDefinition(const std::shared_ptr<AstObject> &node)
220 {
221     auto structName = GenConfigStructName(node);
222     static std::set<std::string> symbolSet;
223 
224     if (symbolSet.find(structName) != symbolSet.end()) {
225         return NOERR;
226     } else {
227         symbolSet.insert(structName);
228     }
229 
230     ofs_ << "struct " << structName << " {\n";
231 
232     auto termIt = node->Child();
233     while (termIt != nullptr) {
234         bool res = GenObjectDefinitionGen(termIt);
235         if (!res) {
236             return res;
237         }
238         termIt = termIt->Next();
239     }
240 
241     ofs_ << "};\n\n";
242 
243     return ofs_.good() ? NOERR : EOUTPUT;
244 }
245 
GenConfigStructName(const std::shared_ptr<AstObject> & node)246 std::string TextGen::GenConfigStructName(const std::shared_ptr<AstObject> &node)
247 {
248     return ToUpperCamelString(prefix_).append(ToUpperCamelString(moduleName_)).append(ToUpperCamelString(node->Name()));
249 }
250 
GenObjectDefinitionGen(const std::shared_ptr<AstObject> & object)251 bool TextGen::GenObjectDefinitionGen(const std::shared_ptr<AstObject> &object)
252 {
253     if (!object->IsNode() && !object->IsTerm()) {
254         return true;
255     }
256 
257     switch (object->Type()) {
258         case PARSEROP_CONFNODE: {
259             auto structName = GenConfigStructName(object);
260             auto node = ConfigNode::CastFrom(object);
261             auto nodeName = ToLowerCamelString(node->Name());
262             if (node->GetNodeType() == NODE_TEMPLATE) {
263                 ofs_ << Indent() << "const struct " << structName << "* " << nodeName << ";\n";
264                 ofs_ << Indent() << "uint16_t " << nodeName << "Size;\n";
265             } else if (node->GetNodeType() == NODE_INHERIT) {
266                 return true;
267             } else {
268                 ofs_ << Indent() << "struct " << structName << " " << nodeName << ";\n";
269             }
270             break;
271         }
272         case PARSEROP_CONFTERM:
273             return GenTermDefinition(object);
274         default:
275             break;
276     }
277 
278     return ofs_.good();
279 }
280 
GenTermDefinition(const std::shared_ptr<AstObject> & term)281 bool TextGen::GenTermDefinition(const std::shared_ptr<AstObject> &term)
282 {
283     auto value = term->Child();
284     switch (value->Type()) {
285         case PARSEROP_ARRAY: {
286             auto array = ConfigArray::CastFrom(value);
287             if (IsInTemplate(term)) {
288                 ofs_ << TAB << "const " << TypeToStr(array->ArrayType()) << "* " << term->Name() << ";\n";
289                 ofs_ << TAB << "uint32_t " << term->Name() << "Size;\n";
290             } else {
291                 ofs_ << TAB << TypeToStr(array->ArrayType()) << " " << term->Name() << "[" << std::dec
292                      << array->ArraySize() << "];\n";
293             }
294             break;
295         }
296         case PARSEROP_UINT8:
297         case PARSEROP_UINT16:
298         case PARSEROP_UINT32:
299         case PARSEROP_UINT64:
300         case PARSEROP_STRING:
301             ofs_ << TAB << TypeToStr(value->Type()) << " " << term->Name() << ";\n";
302             break;
303         case PARSEROP_NODEREF: {
304             auto structName = GenConfigStructName(ConfigTerm::CastFrom(term)->RefNode().lock());
305             ofs_ << TAB << "const struct " << structName << "* " << term->Name() << ";\n";
306             break;
307         }
308         default:
309             break;
310     }
311 
312     return ofs_.good();
313 }
314 
IsInTemplate(const std::shared_ptr<AstObject> & object)315 bool TextGen::IsInTemplate(const std::shared_ptr<AstObject> &object)
316 {
317     auto p = object->Parent();
318     while (p != nullptr) {
319         if (p->IsNode() && ConfigNode::CastFrom(p)->GetNodeType() == NODE_TEMPLATE) {
320             return true;
321         }
322         p = p->Parent();
323     }
324     return false;
325 }
326 
TypeToStr(uint32_t type)327 const std::string &TextGen::TypeToStr(uint32_t type)
328 {
329     static std::map<uint32_t, std::string> typeMap = {
330         {PARSEROP_UINT8,  "uint8_t"    },
331         {PARSEROP_UINT16, "uint16_t"   },
332         {PARSEROP_UINT32, "uint32_t"   },
333         {PARSEROP_UINT64, "uint64_t"   },
334         {PARSEROP_STRING, "const char*"},
335     };
336     return typeMap[type];
337 }
338 
OutputImplGlobalVariables()339 bool TextGen::OutputImplGlobalVariables()
340 {
341     auto forwardWalkFunc = [this](const std::shared_ptr<AstObject> &current, int32_t depth) -> uint32_t {
342         return ImplementGenTraversal(current, depth);
343     };
344 
345     auto backwardWalkFunc = [this](const std::shared_ptr<AstObject> &current, int32_t depth) -> uint32_t {
346         return ImplementCloseBraceGen(current, depth);
347     };
348 
349     return ast_->WalkRound(forwardWalkFunc, backwardWalkFunc);
350 }
351 
Indent(uint32_t times)352 const std::string &TextGen::Indent(uint32_t times)
353 {
354     static std::map<uint32_t, std::string> indentMap;
355     auto indent = indentMap.find(times);
356     if (indent == indentMap.end()) {
357         auto str = std::string();
358         for (uint32_t i = 0; i < times; ++i) {
359             str.append(TAB);
360         }
361         indentMap.emplace(std::pair<uint32_t, std::string>(times, std::move(str)));
362     }
363 
364     return indentMap.at(times);
365 }
366 
ImplementCloseBraceGen(const std::shared_ptr<AstObject> & object,int32_t depth)367 uint32_t TextGen::ImplementCloseBraceGen(const std::shared_ptr<AstObject> &object, int32_t depth)
368 {
369     if (!object->IsNode() || ConfigNode::CastFrom(object)->GetNodeType() == NODE_INHERIT) {
370         return NOERR;
371     }
372     if (object == ast_->GetAstRoot()) {
373         ofs_ << "};\n";
374     } else {
375         ofs_ << Indent(depth) << "},\n";
376     }
377     return ofs_.good() ? NOERR : EOUTPUT;
378 }
379 
ImplementGenTraversal(const std::shared_ptr<AstObject> & object,int32_t depth)380 uint32_t TextGen::ImplementGenTraversal(const std::shared_ptr<AstObject> &object, int32_t depth)
381 {
382     if (!object->IsNode() && !object->IsTerm()) {
383         return NOERR;
384     }
385 
386     if (object->IsTerm() && IsInSubClassNode(object)) {
387         return NOERR;
388     }
389 
390     if (object == ast_->GetAstRoot()) {
391         auto structName = GenConfigStructName(object);
392         ofs_ << "static const struct " << structName << " " << rootVariableName_ << " = {\n";
393         if (object->Child() == nullptr) {
394             ofs_ << "};\n";
395         }
396         return ofs_.good() ? NOERR : EOUTPUT;
397     }
398     return ObjectImplementGen(object, depth);
399 }
400 
IsInSubClassNode(const std::shared_ptr<AstObject> & object)401 bool TextGen::IsInSubClassNode(const std::shared_ptr<AstObject> &object)
402 {
403     std::shared_ptr<AstObject> obj = object;
404     while (obj != nullptr) {
405         if (obj->IsNode() && ConfigNode::CastFrom(obj)->GetNodeType() == NODE_INHERIT) {
406             return true;
407         }
408         obj = obj->Parent();
409     }
410     return false;
411 }
412 
ObjectImplementGen(const std::shared_ptr<AstObject> & object,int32_t depth)413 uint32_t TextGen::ObjectImplementGen(const std::shared_ptr<AstObject> &object, int32_t depth)
414 {
415     switch (object->Type()) {
416         case PARSEROP_CONFNODE: {
417             auto node = ConfigNode::CastFrom(object);
418             if (node->GetNodeType() != NODE_NOREF) {
419                 return TemplateObjectImplGen(object, depth) ? EASTWALKBREAK : EOUTPUT;
420             }
421             ofs_ << Indent(depth) << '.' << node->Name() << " = {\n";
422             if (node->Child() == nullptr) {
423                 ofs_ << Indent(depth) << "},\n";
424             }
425             break;
426         }
427         case PARSEROP_CONFTERM:
428             return PrintTermImplement(object, depth);
429         default:
430             return NOERR;
431     }
432 
433     return ofs_.good() ? NOERR : EOUTPUT;
434 }
435 
TemplateObjectImplGen(const std::shared_ptr<AstObject> & object,int32_t depth)436 bool TextGen::TemplateObjectImplGen(const std::shared_ptr<AstObject> &object, int32_t depth)
437 {
438     auto node = ConfigNode::CastFrom(object);
439     if (node->GetNodeType() != NODE_TEMPLATE) {
440         return true;
441     }
442 
443     std::string varName = GenTemplateVariableName(object);
444     auto nodeName = ToLowerCamelString(node->Name());
445 
446     ofs_ << Indent(depth) << '.' << nodeName << " = ";
447     if (node->InheritCount() != 0) {
448         ofs_ << varName;
449     } else {
450         ofs_ << '0';
451     }
452     ofs_ << ",\n";
453     ofs_ << Indent(depth) << '.' << nodeName << "Size = " << std::dec << node->InheritCount() << ",\n";
454     return ofs_.good();
455 }
456 
GenTemplateVariableName(const std::shared_ptr<AstObject> & object)457 std::string TextGen::GenTemplateVariableName(const std::shared_ptr<AstObject> &object)
458 {
459     auto name = ToUpperCamelString(object->Name());
460     auto sym = SymbolFind(name);
461     auto node = ConfigNode::CastFrom(object);
462     if (sym == nullptr) {
463         SymbolAdd(name, object);
464     } else if (sym->object != object && node->TemplateSignNum() == 0) {
465         sym->duplicateCount++;
466         node->SetTemplateSignNum(sym->duplicateCount);
467     }
468 
469     return node->TemplateSignNum() != 0 ?
470         std::string("g_").append(prefix_).append(name).append(std::to_string(node->TemplateSignNum())) :
471         std::string("g_").append(prefix_).append(name);
472 }
473 
SymbolFind(const std::string & name)474 std::shared_ptr<TextGen::Symbol> TextGen::SymbolFind(const std::string &name)
475 {
476     auto sym = symMap.find(name);
477     return sym == symMap.end() ? nullptr : sym->second;
478 }
479 
SymbolAdd(const std::string & name,const std::shared_ptr<AstObject> & object)480 void TextGen::SymbolAdd(const std::string &name, const std::shared_ptr<AstObject> &object)
481 {
482     auto sym = symMap.find(name);
483     if (sym != symMap.end()) {
484         sym->second->duplicateCount++;
485     }
486     symMap.insert(std::make_pair(std::string(name), std::make_shared<Symbol>(object, 1)));
487 }
488 
PrintTermImplement(const std::shared_ptr<AstObject> & object,int32_t depth)489 uint32_t TextGen::PrintTermImplement(const std::shared_ptr<AstObject> &object, int32_t depth)
490 {
491     auto term = ConfigTerm::CastFrom(object);
492     auto value = object->Child();
493     switch (value->Type()) {
494         case PARSEROP_UINT8:
495         case PARSEROP_UINT16: /* fall-through */
496         case PARSEROP_UINT32: /* fall-through */
497         case PARSEROP_UINT64: /* fall-through */
498         case PARSEROP_STRING:
499             ofs_ << Indent(depth) << '.' << term->Name() << " = ";
500             if (!PrintBaseTypeValue(value)) {
501                 return EOUTPUT;
502             }
503             ofs_ << ",\n";
504             break;
505         case PARSEROP_ARRAY:
506             return PrintArrayImplement(object, depth);
507         case PARSEROP_NODEREF: {
508             std::string refPath = HcsBuildObjectPath(term->RefNode().lock());
509             ofs_ << Indent(depth) << '.' << term->Name() << " = &" << refPath << ",\n";
510             break;
511         }
512         default:
513             break;
514     }
515 
516     return ofs_.good() ? NOERR : EOUTPUT;
517 }
518 
PrintBaseTypeValue(const std::shared_ptr<AstObject> & object)519 bool TextGen::PrintBaseTypeValue(const std::shared_ptr<AstObject> &object)
520 {
521     switch (object->Type()) {
522         case PARSEROP_UINT8:  /* fallthrough */
523         case PARSEROP_UINT16: /* fallthrough */
524         case PARSEROP_UINT32: /* fallthrough */
525         case PARSEROP_UINT64:
526             ofs_ << "0x" << std::hex << object->IntegerValue();
527             break;
528         case PARSEROP_STRING:
529             ofs_ << '"' << object->StringValue() << '"';
530             break;
531         default:
532             break;
533     }
534 
535     return ofs_.good();
536 }
537 
PrintArrayImplement(const std::shared_ptr<AstObject> & object,int32_t depth)538 uint32_t TextGen::PrintArrayImplement(const std::shared_ptr<AstObject> &object, int32_t depth)
539 {
540     if (IsInSubClassNode(object)) {
541         return PrintArrayImplInSubClass(object, depth) ? NOERR : EOUTPUT;
542     }
543 
544     auto termContext = object->Child();
545     ofs_ << Indent(depth) << '.' << object->Name() << " = { ";
546 
547     if (!HcsPrintArrayContent(termContext, depth + 1)) {
548         return EOUTPUT;
549     }
550 
551     ofs_ << " },\n";
552 
553     return ofs_.good() ? NOERR : EOUTPUT;
554 }
555 
PrintArrayImplInSubClass(const std::shared_ptr<AstObject> & object,int32_t depth)556 bool TextGen::PrintArrayImplInSubClass(const std::shared_ptr<AstObject> &object, int32_t depth)
557 {
558     auto array = ConfigArray::CastFrom(object->Child());
559     auto arrayName = GenArrayName(object);
560 
561     ofs_ << Indent(depth) << '.' << object->Name() << " = " << arrayName << ",\n";
562     ofs_ << Indent(depth) << '.' << object->Name() << "Size = " << std::dec << array->ArraySize() << ",\n";
563 
564     return ofs_.good();
565 }
566 
HcsPrintArrayContent(const std::shared_ptr<AstObject> & object,uint32_t indent)567 bool TextGen::HcsPrintArrayContent(const std::shared_ptr<AstObject> &object, uint32_t indent)
568 {
569     constexpr uint32_t elementPerLine = 16;
570     auto element = object->Child();
571     uint32_t elementCount = 0;
572     while (element != nullptr) {
573         if (!PrintBaseTypeValue(element)) {
574             return false;
575         }
576         if (elementCount++ >= elementPerLine) {
577             ofs_ << "\n" << Indent(indent);
578         }
579         element = element->Next();
580         if (element != nullptr) {
581             ofs_ << ", ";
582         }
583     }
584 
585     return ofs_.good();
586 }
587 
HcsBuildObjectPath(std::shared_ptr<AstObject> object)588 std::string TextGen::HcsBuildObjectPath(std::shared_ptr<AstObject> object)
589 {
590     std::list<std::shared_ptr<AstObject>> pathList;
591     auto p = object;
592     while (p != ast_->GetAstRoot()) {
593         pathList.push_back(p);
594         p = p->Parent();
595     }
596 
597     pathList.reverse();
598 
599     std::string path = rootVariableName_;
600     for (auto &it : pathList) {
601         path.append(".").append(it->Name());
602     }
603 
604     return path;
605 }
606 
OutputTemplateImpl()607 bool TextGen::OutputTemplateImpl()
608 {
609     if (!OutputTemplateVariablesDeclare()) {
610         return false;
611     }
612 
613     return ast_->WalkBackward([this](const std::shared_ptr<AstObject> &object, int32_t) -> uint32_t {
614         if (!object->IsNode() || ConfigNode::CastFrom(object)->GetNodeType() != NODE_TEMPLATE) {
615             return NOERR;
616         }
617         auto node = ConfigNode::CastFrom(object);
618         if (node->InheritCount() == 0) {
619             return NOERR;
620         }
621 
622         ofs_ << "static const struct " << GenConfigStructName(object) << ' ' << GenTemplateVariableName(object)
623              << "[] = {\n";
624         auto subClass = node->SubClasses();
625         for (auto nodeObj : subClass) {
626             std::shared_ptr<AstObject> obj = std::shared_ptr<AstObject>(nodeObj, [](auto p) { (void)p; });
627             ofs_ << Indent() << '[' << std::dec << ConfigNode::CastFrom(obj)->InheritIndex() << "] = {\n";
628             if (!TemplateVariableGen(obj)) {
629                 return EOUTPUT;
630             }
631             ofs_ << Indent() << "},\n";
632         }
633 
634         ofs_ << "};\n\n";
635         return ofs_.good() ? NOERR : EOUTPUT;
636     });
637 }
638 
OutputTemplateVariablesDeclare()639 bool TextGen::OutputTemplateVariablesDeclare()
640 {
641     return ast_->WalkBackward([this](const std::shared_ptr<AstObject> &object, int32_t) -> uint32_t {
642         if (object->IsTerm() && object->Child()->IsArray()) {
643             return ArrayVariablesDeclareGen(object);
644         } else if (!object->IsNode() || ConfigNode::CastFrom(object)->GetNodeType() != NODE_TEMPLATE) {
645             return NOERR;
646         }
647         auto node = ConfigNode::CastFrom(object);
648         if (node->InheritCount() == 0) {
649             return NOERR;
650         }
651 
652         auto structName = GenConfigStructName(object);
653         ofs_ << "static const struct " << GenConfigStructName(object) << ' ' << GenTemplateVariableName(object)
654              << "[];\n\n";
655 
656         return ofs_.good() ? NOERR : EOUTPUT;
657     });
658 }
659 
ArrayVariablesDeclareGen(const std::shared_ptr<AstObject> & object)660 uint32_t TextGen::ArrayVariablesDeclareGen(const std::shared_ptr<AstObject> &object)
661 {
662     if (!IsInSubClassNode(object)) {
663         return NOERR;
664     }
665 
666     auto arrayName = GenArrayName(object);
667     auto array = ConfigArray::CastFrom(object->Child());
668     ofs_ << "static const " << TypeToStr(array->ArrayType()) << ' ' << arrayName << '[' << std::dec
669          << array->ArraySize() << "] = {\n"
670          << Indent();
671     HcsPrintArrayContent(object->Child(), 1);
672     ofs_ << "\n};\n\n";
673 
674     return ofs_.good() ? NOERR : EOUTPUT;
675 }
676 
GenArrayName(const std::shared_ptr<AstObject> & term)677 std::string TextGen::GenArrayName(const std::shared_ptr<AstObject> &term)
678 {
679     auto arrayName = std::string("g_hcsConfigArray").append(ToUpperCamelString(term->Name()));
680     auto t = ConfigTerm::CastFrom(term);
681     auto sym = SymbolFind(arrayName);
682     if (sym == nullptr) {
683         SymbolAdd(arrayName, term);
684         t->SetSigNum(1);
685     } else if (t->SigNum() == 0) {
686         t->SetSigNum(sym->duplicateCount + 1);
687         sym->duplicateCount++;
688     }
689 
690     arrayName.append(std::to_string(t->SigNum()));
691     return arrayName;
692 }
693 
TemplateVariableGen(const std::shared_ptr<AstObject> & nodeObject)694 uint32_t TextGen::TemplateVariableGen(const std::shared_ptr<AstObject> &nodeObject)
695 {
696     auto child = nodeObject->Child();
697     while (child != nullptr) {
698         auto res = Ast::WalkRound(
699             child,
700             [this](const std::shared_ptr<AstObject> &object, uint32_t depth) -> uint32_t {
701                 return ObjectImplementGen(object, depth + 2);
702             },
703             [this](const std::shared_ptr<AstObject> &object, uint32_t depth) -> uint32_t {
704                 return ImplementCloseBraceGen(object, depth + 2);
705             });
706         if (!res) {
707             return false;
708         }
709         child = child->Next();
710     }
711     return true;
712 }
713 
DuplicateNodeNameCheck()714 bool TextGen::DuplicateNodeNameCheck()
715 {
716     std::map<std::string, std::shared_ptr<AstObject>> nodeMap;
717 
718     return ast_->WalkForward([&nodeMap](const std::shared_ptr<AstObject> &current, uint32_t) -> uint32_t {
719         if (!current->IsNode() || IsInSubClassNode(current)) {
720             return NOERR;
721         }
722 
723         auto node = nodeMap.find(current->Name());
724         if (node == nodeMap.end()) {
725             nodeMap[current->Name()] = current;
726             return NOERR;
727         }
728 
729         Logger().Error() << current->SourceInfo() << "duplicate node name at " << node->second->SourceInfo() << "\n"
730                          << "To avoid redefining structures, not allow duplicate node name at text config mode";
731         return EFAIL;
732     });
733 }
734