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> ¤t, 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> ¤t, int32_t depth) -> uint32_t {
342 return ImplementGenTraversal(current, depth);
343 };
344
345 auto backwardWalkFunc = [this](const std::shared_ptr<AstObject> ¤t, 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> ¤t, 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