xref: /aosp_15_r20/external/openscreen/tools/cddl/sema.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard // Copyright 2018 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard 
5*3f982cf4SFabien Sanglard #include "tools/cddl/sema.h"
6*3f982cf4SFabien Sanglard 
7*3f982cf4SFabien Sanglard #include <string.h>
8*3f982cf4SFabien Sanglard #include <unistd.h>
9*3f982cf4SFabien Sanglard 
10*3f982cf4SFabien Sanglard #include <cinttypes>
11*3f982cf4SFabien Sanglard #include <cstdlib>
12*3f982cf4SFabien Sanglard #include <iostream>
13*3f982cf4SFabien Sanglard #include <map>
14*3f982cf4SFabien Sanglard #include <memory>
15*3f982cf4SFabien Sanglard #include <string>
16*3f982cf4SFabien Sanglard #include <unordered_set>
17*3f982cf4SFabien Sanglard #include <vector>
18*3f982cf4SFabien Sanglard 
19*3f982cf4SFabien Sanglard #include "absl/algorithm/container.h"
20*3f982cf4SFabien Sanglard #include "absl/strings/numbers.h"
21*3f982cf4SFabien Sanglard #include "absl/strings/string_view.h"
22*3f982cf4SFabien Sanglard #include "absl/types/optional.h"
23*3f982cf4SFabien Sanglard #include "tools/cddl/logging.h"
24*3f982cf4SFabien Sanglard 
TypesWithId()25*3f982cf4SFabien Sanglard std::vector<CppType*> CppSymbolTable::TypesWithId() {
26*3f982cf4SFabien Sanglard   if (!this->TypesWithId_.size()) {
27*3f982cf4SFabien Sanglard     for (const std::unique_ptr<CppType>& ptr : this->cpp_types) {
28*3f982cf4SFabien Sanglard       if (ptr->type_key == absl::nullopt) {
29*3f982cf4SFabien Sanglard         continue;
30*3f982cf4SFabien Sanglard       }
31*3f982cf4SFabien Sanglard       this->TypesWithId_.emplace_back(ptr.get());
32*3f982cf4SFabien Sanglard     }
33*3f982cf4SFabien Sanglard   }
34*3f982cf4SFabien Sanglard   return this->TypesWithId_;
35*3f982cf4SFabien Sanglard }
36*3f982cf4SFabien Sanglard 
CddlType()37*3f982cf4SFabien Sanglard CddlType::CddlType()
38*3f982cf4SFabien Sanglard     : map(nullptr), op(CddlType::Op::kNone), constraint_type(nullptr) {}
~CddlType()39*3f982cf4SFabien Sanglard CddlType::~CddlType() {
40*3f982cf4SFabien Sanglard   switch (which) {
41*3f982cf4SFabien Sanglard     case CddlType::Which::kDirectChoice:
42*3f982cf4SFabien Sanglard       direct_choice.std::vector<CddlType*>::~vector();
43*3f982cf4SFabien Sanglard       break;
44*3f982cf4SFabien Sanglard     case CddlType::Which::kValue:
45*3f982cf4SFabien Sanglard       value.std::string::~basic_string();
46*3f982cf4SFabien Sanglard       break;
47*3f982cf4SFabien Sanglard     case CddlType::Which::kId:
48*3f982cf4SFabien Sanglard       id.std::string::~basic_string();
49*3f982cf4SFabien Sanglard       break;
50*3f982cf4SFabien Sanglard     case CddlType::Which::kMap:
51*3f982cf4SFabien Sanglard       break;
52*3f982cf4SFabien Sanglard     case CddlType::Which::kArray:
53*3f982cf4SFabien Sanglard       break;
54*3f982cf4SFabien Sanglard     case CddlType::Which::kGroupChoice:
55*3f982cf4SFabien Sanglard       break;
56*3f982cf4SFabien Sanglard     case CddlType::Which::kGroupnameChoice:
57*3f982cf4SFabien Sanglard       break;
58*3f982cf4SFabien Sanglard     case CddlType::Which::kTaggedType:
59*3f982cf4SFabien Sanglard       tagged_type.~TaggedType();
60*3f982cf4SFabien Sanglard       break;
61*3f982cf4SFabien Sanglard   }
62*3f982cf4SFabien Sanglard }
63*3f982cf4SFabien Sanglard 
Entry()64*3f982cf4SFabien Sanglard CddlGroup::Entry::Entry() : group(nullptr) {}
~Entry()65*3f982cf4SFabien Sanglard CddlGroup::Entry::~Entry() {
66*3f982cf4SFabien Sanglard   switch (which) {
67*3f982cf4SFabien Sanglard     case CddlGroup::Entry::Which::kUninitialized:
68*3f982cf4SFabien Sanglard       break;
69*3f982cf4SFabien Sanglard     case CddlGroup::Entry::Which::kType:
70*3f982cf4SFabien Sanglard       type.~EntryType();
71*3f982cf4SFabien Sanglard       break;
72*3f982cf4SFabien Sanglard     case CddlGroup::Entry::Which::kGroup:
73*3f982cf4SFabien Sanglard       break;
74*3f982cf4SFabien Sanglard   }
75*3f982cf4SFabien Sanglard }
76*3f982cf4SFabien Sanglard 
CppType()77*3f982cf4SFabien Sanglard CppType::CppType() : vector_type() {}
~CppType()78*3f982cf4SFabien Sanglard CppType::~CppType() {
79*3f982cf4SFabien Sanglard   switch (which) {
80*3f982cf4SFabien Sanglard     case CppType::Which::kUninitialized:
81*3f982cf4SFabien Sanglard       break;
82*3f982cf4SFabien Sanglard     case CppType::Which::kUint64:
83*3f982cf4SFabien Sanglard       break;
84*3f982cf4SFabien Sanglard     case CppType::Which::kString:
85*3f982cf4SFabien Sanglard       break;
86*3f982cf4SFabien Sanglard     case CppType::Which::kBytes:
87*3f982cf4SFabien Sanglard       break;
88*3f982cf4SFabien Sanglard     case CppType::Which::kVector:
89*3f982cf4SFabien Sanglard       break;
90*3f982cf4SFabien Sanglard     case CppType::Which::kEnum:
91*3f982cf4SFabien Sanglard       enum_type.~Enum();
92*3f982cf4SFabien Sanglard       break;
93*3f982cf4SFabien Sanglard     case CppType::Which::kStruct:
94*3f982cf4SFabien Sanglard       struct_type.~Struct();
95*3f982cf4SFabien Sanglard       break;
96*3f982cf4SFabien Sanglard     case CppType::Which::kOptional:
97*3f982cf4SFabien Sanglard       break;
98*3f982cf4SFabien Sanglard     case CppType::Which::kDiscriminatedUnion:
99*3f982cf4SFabien Sanglard       discriminated_union.~DiscriminatedUnion();
100*3f982cf4SFabien Sanglard       break;
101*3f982cf4SFabien Sanglard     case CppType::Which::kTaggedType:
102*3f982cf4SFabien Sanglard       break;
103*3f982cf4SFabien Sanglard   }
104*3f982cf4SFabien Sanglard }
105*3f982cf4SFabien Sanglard 
InitVector()106*3f982cf4SFabien Sanglard void CppType::InitVector() {
107*3f982cf4SFabien Sanglard   which = Which::kVector;
108*3f982cf4SFabien Sanglard   new (&vector_type) Vector();
109*3f982cf4SFabien Sanglard }
110*3f982cf4SFabien Sanglard 
InitEnum()111*3f982cf4SFabien Sanglard void CppType::InitEnum() {
112*3f982cf4SFabien Sanglard   which = Which::kEnum;
113*3f982cf4SFabien Sanglard   new (&enum_type) Enum();
114*3f982cf4SFabien Sanglard }
115*3f982cf4SFabien Sanglard 
InitStruct()116*3f982cf4SFabien Sanglard void CppType::InitStruct() {
117*3f982cf4SFabien Sanglard   which = Which::kStruct;
118*3f982cf4SFabien Sanglard   new (&struct_type) Struct();
119*3f982cf4SFabien Sanglard }
120*3f982cf4SFabien Sanglard 
InitDiscriminatedUnion()121*3f982cf4SFabien Sanglard void CppType::InitDiscriminatedUnion() {
122*3f982cf4SFabien Sanglard   which = Which::kDiscriminatedUnion;
123*3f982cf4SFabien Sanglard   new (&discriminated_union) DiscriminatedUnion();
124*3f982cf4SFabien Sanglard }
125*3f982cf4SFabien Sanglard 
InitBytes()126*3f982cf4SFabien Sanglard void CppType::InitBytes() {
127*3f982cf4SFabien Sanglard   which = Which::kBytes;
128*3f982cf4SFabien Sanglard }
129*3f982cf4SFabien Sanglard 
InitString(std::string * s,absl::string_view value)130*3f982cf4SFabien Sanglard void InitString(std::string* s, absl::string_view value) {
131*3f982cf4SFabien Sanglard   new (s) std::string(value);
132*3f982cf4SFabien Sanglard }
133*3f982cf4SFabien Sanglard 
InitDirectChoice(std::vector<CddlType * > * direct_choice)134*3f982cf4SFabien Sanglard void InitDirectChoice(std::vector<CddlType*>* direct_choice) {
135*3f982cf4SFabien Sanglard   new (direct_choice) std::vector<CddlType*>();
136*3f982cf4SFabien Sanglard }
137*3f982cf4SFabien Sanglard 
InitGroupEntry(CddlGroup::Entry::EntryType * entry)138*3f982cf4SFabien Sanglard void InitGroupEntry(CddlGroup::Entry::EntryType* entry) {
139*3f982cf4SFabien Sanglard   new (entry) CddlGroup::Entry::EntryType();
140*3f982cf4SFabien Sanglard }
141*3f982cf4SFabien Sanglard 
AddCddlType(CddlSymbolTable * table,CddlType::Which which)142*3f982cf4SFabien Sanglard CddlType* AddCddlType(CddlSymbolTable* table, CddlType::Which which) {
143*3f982cf4SFabien Sanglard   table->types.emplace_back(new CddlType);
144*3f982cf4SFabien Sanglard   CddlType* value = table->types.back().get();
145*3f982cf4SFabien Sanglard   value->which = which;
146*3f982cf4SFabien Sanglard   return value;
147*3f982cf4SFabien Sanglard }
148*3f982cf4SFabien Sanglard 
149*3f982cf4SFabien Sanglard CddlType* AnalyzeType(CddlSymbolTable* table, const AstNode& type);
150*3f982cf4SFabien Sanglard CddlGroup* AnalyzeGroup(CddlSymbolTable* table, const AstNode& group);
151*3f982cf4SFabien Sanglard 
AnalyzeType2(CddlSymbolTable * table,const AstNode & type2)152*3f982cf4SFabien Sanglard CddlType* AnalyzeType2(CddlSymbolTable* table, const AstNode& type2) {
153*3f982cf4SFabien Sanglard   const AstNode* node = type2.children;
154*3f982cf4SFabien Sanglard   if (node->type == AstNode::Type::kNumber ||
155*3f982cf4SFabien Sanglard       node->type == AstNode::Type::kText ||
156*3f982cf4SFabien Sanglard       node->type == AstNode::Type::kBytes) {
157*3f982cf4SFabien Sanglard     CddlType* value = AddCddlType(table, CddlType::Which::kValue);
158*3f982cf4SFabien Sanglard     InitString(&value->value, node->text);
159*3f982cf4SFabien Sanglard     return value;
160*3f982cf4SFabien Sanglard   } else if (node->type == AstNode::Type::kTypename) {
161*3f982cf4SFabien Sanglard     if (type2.text[0] == '~') {
162*3f982cf4SFabien Sanglard       dprintf(STDERR_FILENO, "We don't support the '~' operator.\n");
163*3f982cf4SFabien Sanglard       return nullptr;
164*3f982cf4SFabien Sanglard     }
165*3f982cf4SFabien Sanglard     CddlType* id = AddCddlType(table, CddlType::Which::kId);
166*3f982cf4SFabien Sanglard     InitString(&id->id, node->text);
167*3f982cf4SFabien Sanglard     return id;
168*3f982cf4SFabien Sanglard   } else if (node->type == AstNode::Type::kType) {
169*3f982cf4SFabien Sanglard     if (type2.text[0] == '#' && type2.text[1] == '6' && type2.text[2] == '.') {
170*3f982cf4SFabien Sanglard       CddlType* tagged_type = AddCddlType(table, CddlType::Which::kTaggedType);
171*3f982cf4SFabien Sanglard       tagged_type->tagged_type.tag_value =
172*3f982cf4SFabien Sanglard           atoll(type2.text.substr(3 /* #6. */).data());
173*3f982cf4SFabien Sanglard       tagged_type->tagged_type.type = AnalyzeType(table, *node);
174*3f982cf4SFabien Sanglard       return tagged_type;
175*3f982cf4SFabien Sanglard     }
176*3f982cf4SFabien Sanglard     dprintf(STDERR_FILENO, "Unknown type2 value, expected #6.[uint]\n");
177*3f982cf4SFabien Sanglard   } else if (node->type == AstNode::Type::kGroup) {
178*3f982cf4SFabien Sanglard     if (type2.text[0] == '{') {
179*3f982cf4SFabien Sanglard       CddlType* map = AddCddlType(table, CddlType::Which::kMap);
180*3f982cf4SFabien Sanglard       map->map = AnalyzeGroup(table, *node);
181*3f982cf4SFabien Sanglard       return map;
182*3f982cf4SFabien Sanglard     } else if (type2.text[0] == '[') {
183*3f982cf4SFabien Sanglard       CddlType* array = AddCddlType(table, CddlType::Which::kArray);
184*3f982cf4SFabien Sanglard       array->array = AnalyzeGroup(table, *node);
185*3f982cf4SFabien Sanglard       return array;
186*3f982cf4SFabien Sanglard     } else if (type2.text[0] == '&') {
187*3f982cf4SFabien Sanglard       // Represents a choice between options in this group (ie an enum), not a
188*3f982cf4SFabien Sanglard       // choice between groups (which is currently unsupported).
189*3f982cf4SFabien Sanglard       CddlType* group_choice =
190*3f982cf4SFabien Sanglard           AddCddlType(table, CddlType::Which::kGroupChoice);
191*3f982cf4SFabien Sanglard       group_choice->group_choice = AnalyzeGroup(table, *node);
192*3f982cf4SFabien Sanglard       return group_choice;
193*3f982cf4SFabien Sanglard     }
194*3f982cf4SFabien Sanglard   } else if (node->type == AstNode::Type::kGroupname) {
195*3f982cf4SFabien Sanglard     if (type2.text[0] == '&') {
196*3f982cf4SFabien Sanglard       CddlType* group_choice =
197*3f982cf4SFabien Sanglard           AddCddlType(table, CddlType::Which::kGroupnameChoice);
198*3f982cf4SFabien Sanglard       InitString(&group_choice->id, node->text);
199*3f982cf4SFabien Sanglard       return group_choice;
200*3f982cf4SFabien Sanglard     }
201*3f982cf4SFabien Sanglard   }
202*3f982cf4SFabien Sanglard   return nullptr;
203*3f982cf4SFabien Sanglard }
204*3f982cf4SFabien Sanglard 
AnalyzeRangeop(const AstNode & rangeop)205*3f982cf4SFabien Sanglard CddlType::Op AnalyzeRangeop(const AstNode& rangeop) {
206*3f982cf4SFabien Sanglard   if (rangeop.text == "..") {
207*3f982cf4SFabien Sanglard     return CddlType::Op::kInclusiveRange;
208*3f982cf4SFabien Sanglard   } else if (rangeop.text == "...") {
209*3f982cf4SFabien Sanglard     return CddlType::Op::kExclusiveRange;
210*3f982cf4SFabien Sanglard   } else {
211*3f982cf4SFabien Sanglard     dprintf(STDERR_FILENO, "Unsupported '%s' range operator.\n",
212*3f982cf4SFabien Sanglard             rangeop.text.c_str());
213*3f982cf4SFabien Sanglard     return CddlType::Op::kNone;
214*3f982cf4SFabien Sanglard   }
215*3f982cf4SFabien Sanglard }
216*3f982cf4SFabien Sanglard 
AnalyzeCtlop(const AstNode & ctlop)217*3f982cf4SFabien Sanglard CddlType::Op AnalyzeCtlop(const AstNode& ctlop) {
218*3f982cf4SFabien Sanglard   if (!ctlop.children) {
219*3f982cf4SFabien Sanglard     dprintf(STDERR_FILENO, "Missing id for control operator '%s'.\n",
220*3f982cf4SFabien Sanglard             ctlop.text.c_str());
221*3f982cf4SFabien Sanglard     return CddlType::Op::kNone;
222*3f982cf4SFabien Sanglard   }
223*3f982cf4SFabien Sanglard   const std::string& id = ctlop.children->text;
224*3f982cf4SFabien Sanglard   if (id == "size") {
225*3f982cf4SFabien Sanglard     return CddlType::Op::kSize;
226*3f982cf4SFabien Sanglard   } else if (id == "bits") {
227*3f982cf4SFabien Sanglard     return CddlType::Op::kBits;
228*3f982cf4SFabien Sanglard   } else if (id == "regexp") {
229*3f982cf4SFabien Sanglard     return CddlType::Op::kRegexp;
230*3f982cf4SFabien Sanglard   } else if (id == "cbor") {
231*3f982cf4SFabien Sanglard     return CddlType::Op::kCbor;
232*3f982cf4SFabien Sanglard   } else if (id == "cborseq") {
233*3f982cf4SFabien Sanglard     return CddlType::Op::kCborseq;
234*3f982cf4SFabien Sanglard   } else if (id == "within") {
235*3f982cf4SFabien Sanglard     return CddlType::Op::kWithin;
236*3f982cf4SFabien Sanglard   } else if (id == "and") {
237*3f982cf4SFabien Sanglard     return CddlType::Op::kAnd;
238*3f982cf4SFabien Sanglard   } else if (id == "lt") {
239*3f982cf4SFabien Sanglard     return CddlType::Op::kLess;
240*3f982cf4SFabien Sanglard   } else if (id == "le") {
241*3f982cf4SFabien Sanglard     return CddlType::Op::kLessOrEqual;
242*3f982cf4SFabien Sanglard   } else if (id == "gt") {
243*3f982cf4SFabien Sanglard     return CddlType::Op::kGreater;
244*3f982cf4SFabien Sanglard   } else if (id == "ge") {
245*3f982cf4SFabien Sanglard     return CddlType::Op::kGreaterOrEqual;
246*3f982cf4SFabien Sanglard   } else if (id == "eq") {
247*3f982cf4SFabien Sanglard     return CddlType::Op::kEqual;
248*3f982cf4SFabien Sanglard   } else if (id == "ne") {
249*3f982cf4SFabien Sanglard     return CddlType::Op::kNotEqual;
250*3f982cf4SFabien Sanglard   } else if (id == "default") {
251*3f982cf4SFabien Sanglard     return CddlType::Op::kDefault;
252*3f982cf4SFabien Sanglard   } else {
253*3f982cf4SFabien Sanglard     dprintf(STDERR_FILENO, "Unsupported '%s' control operator.\n",
254*3f982cf4SFabien Sanglard             ctlop.text.c_str());
255*3f982cf4SFabien Sanglard     return CddlType::Op::kNone;
256*3f982cf4SFabien Sanglard   }
257*3f982cf4SFabien Sanglard }
258*3f982cf4SFabien Sanglard 
259*3f982cf4SFabien Sanglard // Produces CddlType by analyzing AST parsed from type1 rule
260*3f982cf4SFabien Sanglard // ABNF rule: type1 = type2 [S (rangeop / ctlop) S type2]
AnalyzeType1(CddlSymbolTable * table,const AstNode & type1)261*3f982cf4SFabien Sanglard CddlType* AnalyzeType1(CddlSymbolTable* table, const AstNode& type1) {
262*3f982cf4SFabien Sanglard   if (!type1.children) {
263*3f982cf4SFabien Sanglard     dprintf(STDERR_FILENO, "Missing type2 in type1 '%s'.\n",
264*3f982cf4SFabien Sanglard             type1.text.c_str());
265*3f982cf4SFabien Sanglard     return nullptr;
266*3f982cf4SFabien Sanglard   }
267*3f982cf4SFabien Sanglard   const AstNode& target_type = *type1.children;
268*3f982cf4SFabien Sanglard   CddlType* analyzed_type = AnalyzeType2(table, target_type);
269*3f982cf4SFabien Sanglard   if (!analyzed_type) {
270*3f982cf4SFabien Sanglard     dprintf(STDERR_FILENO, "Invalid type2 '%s' in type1 '%s'.\n",
271*3f982cf4SFabien Sanglard             target_type.text.c_str(), type1.text.c_str());
272*3f982cf4SFabien Sanglard     return nullptr;
273*3f982cf4SFabien Sanglard   }
274*3f982cf4SFabien Sanglard   if (!target_type.sibling) {
275*3f982cf4SFabien Sanglard     // No optional range or control operator, return type as-is
276*3f982cf4SFabien Sanglard     return analyzed_type;
277*3f982cf4SFabien Sanglard   }
278*3f982cf4SFabien Sanglard   const AstNode& operator_type = *target_type.sibling;
279*3f982cf4SFabien Sanglard   CddlType::Op op;
280*3f982cf4SFabien Sanglard   if (operator_type.type == AstNode::Type::kRangeop) {
281*3f982cf4SFabien Sanglard     op = AnalyzeRangeop(operator_type);
282*3f982cf4SFabien Sanglard   } else if (operator_type.type == AstNode::Type::kCtlop) {
283*3f982cf4SFabien Sanglard     op = AnalyzeCtlop(operator_type);
284*3f982cf4SFabien Sanglard   } else {
285*3f982cf4SFabien Sanglard     op = CddlType::Op::kNone;
286*3f982cf4SFabien Sanglard   }
287*3f982cf4SFabien Sanglard   if (op == CddlType::Op::kNone) {
288*3f982cf4SFabien Sanglard     dprintf(STDERR_FILENO,
289*3f982cf4SFabien Sanglard             "Unsupported or missing operator '%s' in type1 '%s'.\n",
290*3f982cf4SFabien Sanglard             operator_type.text.c_str(), type1.text.c_str());
291*3f982cf4SFabien Sanglard     return nullptr;
292*3f982cf4SFabien Sanglard   }
293*3f982cf4SFabien Sanglard   if (!operator_type.sibling) {
294*3f982cf4SFabien Sanglard     dprintf(STDERR_FILENO,
295*3f982cf4SFabien Sanglard             "Missing controller type for operator '%s' in type1 '%s'.\n",
296*3f982cf4SFabien Sanglard             operator_type.text.c_str(), type1.text.c_str());
297*3f982cf4SFabien Sanglard     return nullptr;
298*3f982cf4SFabien Sanglard   }
299*3f982cf4SFabien Sanglard   const AstNode& controller_type = *operator_type.sibling;
300*3f982cf4SFabien Sanglard   CddlType* constraint_type = AnalyzeType2(table, controller_type);
301*3f982cf4SFabien Sanglard   if (!constraint_type) {
302*3f982cf4SFabien Sanglard     dprintf(STDERR_FILENO,
303*3f982cf4SFabien Sanglard             "Invalid controller type '%s' for operator '%s' in type1 '%s'.\n",
304*3f982cf4SFabien Sanglard             controller_type.text.c_str(), operator_type.text.c_str(),
305*3f982cf4SFabien Sanglard             type1.text.c_str());
306*3f982cf4SFabien Sanglard     return nullptr;
307*3f982cf4SFabien Sanglard   }
308*3f982cf4SFabien Sanglard   analyzed_type->op = op;
309*3f982cf4SFabien Sanglard   analyzed_type->constraint_type = constraint_type;
310*3f982cf4SFabien Sanglard   return analyzed_type;
311*3f982cf4SFabien Sanglard }
312*3f982cf4SFabien Sanglard 
AnalyzeType(CddlSymbolTable * table,const AstNode & type)313*3f982cf4SFabien Sanglard CddlType* AnalyzeType(CddlSymbolTable* table, const AstNode& type) {
314*3f982cf4SFabien Sanglard   const AstNode* type1 = type.children;
315*3f982cf4SFabien Sanglard   if (type1->sibling) {
316*3f982cf4SFabien Sanglard     // If the type we are looking at has a type choice, create a top-level
317*3f982cf4SFabien Sanglard     // choice object, with a vector containing all valid choices.
318*3f982cf4SFabien Sanglard     CddlType* type_choice = AddCddlType(table, CddlType::Which::kDirectChoice);
319*3f982cf4SFabien Sanglard     InitDirectChoice(&type_choice->direct_choice);
320*3f982cf4SFabien Sanglard     while (type1) {
321*3f982cf4SFabien Sanglard       type_choice->direct_choice.push_back(AnalyzeType1(table, *type1));
322*3f982cf4SFabien Sanglard       type1 = type1->sibling;
323*3f982cf4SFabien Sanglard     }
324*3f982cf4SFabien Sanglard     return type_choice;
325*3f982cf4SFabien Sanglard   } else {
326*3f982cf4SFabien Sanglard     // Else just return the single choice.
327*3f982cf4SFabien Sanglard     return AnalyzeType1(table, *type1);
328*3f982cf4SFabien Sanglard   }
329*3f982cf4SFabien Sanglard }
330*3f982cf4SFabien Sanglard 
331*3f982cf4SFabien Sanglard bool AnalyzeGroupEntry(CddlSymbolTable* table,
332*3f982cf4SFabien Sanglard                        const AstNode& group_entry,
333*3f982cf4SFabien Sanglard                        CddlGroup::Entry* entry);
334*3f982cf4SFabien Sanglard 
AnalyzeGroup(CddlSymbolTable * table,const AstNode & group)335*3f982cf4SFabien Sanglard CddlGroup* AnalyzeGroup(CddlSymbolTable* table, const AstNode& group) {
336*3f982cf4SFabien Sanglard   // NOTE: |group.children| is a grpchoice, which we don't currently handle.
337*3f982cf4SFabien Sanglard   // Therefore, we assume it has no siblings and move on to immediately handling
338*3f982cf4SFabien Sanglard   // its grpent children.
339*3f982cf4SFabien Sanglard   const AstNode* node = group.children->children;
340*3f982cf4SFabien Sanglard   table->groups.emplace_back(new CddlGroup);
341*3f982cf4SFabien Sanglard   CddlGroup* group_def = table->groups.back().get();
342*3f982cf4SFabien Sanglard   while (node) {
343*3f982cf4SFabien Sanglard     group_def->entries.emplace_back(new CddlGroup::Entry);
344*3f982cf4SFabien Sanglard     AnalyzeGroupEntry(table, *node, group_def->entries.back().get());
345*3f982cf4SFabien Sanglard     node = node->sibling;
346*3f982cf4SFabien Sanglard   }
347*3f982cf4SFabien Sanglard   return group_def;
348*3f982cf4SFabien Sanglard }
349*3f982cf4SFabien Sanglard 
350*3f982cf4SFabien Sanglard // Parses a string into an optional uint64_t, with the value being that
351*3f982cf4SFabien Sanglard // represented by the string if it is present and nullopt if it cannot
352*3f982cf4SFabien Sanglard // be parsed.
353*3f982cf4SFabien Sanglard // TODO(rwkeane): Add support for hex and binary options.
ParseOptionalUint(const std::string & text)354*3f982cf4SFabien Sanglard absl::optional<uint64_t> ParseOptionalUint(const std::string& text) {
355*3f982cf4SFabien Sanglard   if (text == "0") {
356*3f982cf4SFabien Sanglard     return 0;
357*3f982cf4SFabien Sanglard   }
358*3f982cf4SFabien Sanglard 
359*3f982cf4SFabien Sanglard   uint64_t parsed = std::strtoul(text.c_str(), nullptr, 10);
360*3f982cf4SFabien Sanglard   if (!parsed) {
361*3f982cf4SFabien Sanglard     return absl::nullopt;
362*3f982cf4SFabien Sanglard   }
363*3f982cf4SFabien Sanglard   return parsed;
364*3f982cf4SFabien Sanglard }
365*3f982cf4SFabien Sanglard 
AnalyzeGroupEntry(CddlSymbolTable * table,const AstNode & group_entry,CddlGroup::Entry * entry)366*3f982cf4SFabien Sanglard bool AnalyzeGroupEntry(CddlSymbolTable* table,
367*3f982cf4SFabien Sanglard                        const AstNode& group_entry,
368*3f982cf4SFabien Sanglard                        CddlGroup::Entry* entry) {
369*3f982cf4SFabien Sanglard   const AstNode* node = group_entry.children;
370*3f982cf4SFabien Sanglard 
371*3f982cf4SFabien Sanglard   // If it's an occurance operator (so the entry is optional), mark it as such
372*3f982cf4SFabien Sanglard   // and proceed to the next the node.
373*3f982cf4SFabien Sanglard   if (node->type == AstNode::Type::kOccur) {
374*3f982cf4SFabien Sanglard     if (node->text == "?") {
375*3f982cf4SFabien Sanglard       entry->opt_occurrence_min = CddlGroup::Entry::kOccurrenceMinUnbounded;
376*3f982cf4SFabien Sanglard       entry->opt_occurrence_max = 1;
377*3f982cf4SFabien Sanglard     } else if (node->text == "+") {
378*3f982cf4SFabien Sanglard       entry->opt_occurrence_min = 1;
379*3f982cf4SFabien Sanglard       entry->opt_occurrence_max = CddlGroup::Entry::kOccurrenceMaxUnbounded;
380*3f982cf4SFabien Sanglard     } else {
381*3f982cf4SFabien Sanglard       auto index = node->text.find('*');
382*3f982cf4SFabien Sanglard       if (index == std::string::npos) {
383*3f982cf4SFabien Sanglard         return false;
384*3f982cf4SFabien Sanglard       }
385*3f982cf4SFabien Sanglard 
386*3f982cf4SFabien Sanglard       int lower_bound = CddlGroup::Entry::kOccurrenceMinUnbounded;
387*3f982cf4SFabien Sanglard       std::string first_half = node->text.substr(0, index);
388*3f982cf4SFabien Sanglard       if ((first_half.length() != 1 || first_half.at(0) != '0') &&
389*3f982cf4SFabien Sanglard           first_half.length() != 0) {
390*3f982cf4SFabien Sanglard         lower_bound = std::atoi(first_half.c_str());
391*3f982cf4SFabien Sanglard         if (!lower_bound) {
392*3f982cf4SFabien Sanglard           return false;
393*3f982cf4SFabien Sanglard         }
394*3f982cf4SFabien Sanglard       }
395*3f982cf4SFabien Sanglard 
396*3f982cf4SFabien Sanglard       int upper_bound = CddlGroup::Entry::kOccurrenceMaxUnbounded;
397*3f982cf4SFabien Sanglard       std::string second_half =
398*3f982cf4SFabien Sanglard           index >= node->text.length() ? "" : node->text.substr(index + 1);
399*3f982cf4SFabien Sanglard       if ((second_half.length() != 1 || second_half.at(0) != '0') &&
400*3f982cf4SFabien Sanglard           second_half.length() != 0) {
401*3f982cf4SFabien Sanglard         upper_bound = std::atoi(second_half.c_str());
402*3f982cf4SFabien Sanglard         if (!upper_bound) {
403*3f982cf4SFabien Sanglard           return false;
404*3f982cf4SFabien Sanglard         }
405*3f982cf4SFabien Sanglard       }
406*3f982cf4SFabien Sanglard 
407*3f982cf4SFabien Sanglard       entry->opt_occurrence_min = lower_bound;
408*3f982cf4SFabien Sanglard       entry->opt_occurrence_max = upper_bound;
409*3f982cf4SFabien Sanglard     }
410*3f982cf4SFabien Sanglard     entry->occurrence_specified = true;
411*3f982cf4SFabien Sanglard     node = node->sibling;
412*3f982cf4SFabien Sanglard   } else {
413*3f982cf4SFabien Sanglard     entry->opt_occurrence_min = 1;
414*3f982cf4SFabien Sanglard     entry->opt_occurrence_max = 1;
415*3f982cf4SFabien Sanglard     entry->occurrence_specified = false;
416*3f982cf4SFabien Sanglard   }
417*3f982cf4SFabien Sanglard 
418*3f982cf4SFabien Sanglard   // If it's a member key (key in a map), save it and go to next node.
419*3f982cf4SFabien Sanglard   if (node->type == AstNode::Type::kMemberKey) {
420*3f982cf4SFabien Sanglard     if (node->text[node->text.size() - 1] == '>')
421*3f982cf4SFabien Sanglard       return false;
422*3f982cf4SFabien Sanglard     entry->which = CddlGroup::Entry::Which::kType;
423*3f982cf4SFabien Sanglard     InitGroupEntry(&entry->type);
424*3f982cf4SFabien Sanglard     entry->type.opt_key = std::string(node->children->text);
425*3f982cf4SFabien Sanglard     entry->type.integer_key = ParseOptionalUint(node->integer_member_key_text);
426*3f982cf4SFabien Sanglard     node = node->sibling;
427*3f982cf4SFabien Sanglard   }
428*3f982cf4SFabien Sanglard 
429*3f982cf4SFabien Sanglard   // If it's a type, process it as such.
430*3f982cf4SFabien Sanglard   if (node->type == AstNode::Type::kType) {
431*3f982cf4SFabien Sanglard     if (entry->which == CddlGroup::Entry::Which::kUninitialized) {
432*3f982cf4SFabien Sanglard       entry->which = CddlGroup::Entry::Which::kType;
433*3f982cf4SFabien Sanglard       InitGroupEntry(&entry->type);
434*3f982cf4SFabien Sanglard     }
435*3f982cf4SFabien Sanglard     entry->type.value = AnalyzeType(table, *node);
436*3f982cf4SFabien Sanglard   } else if (node->type == AstNode::Type::kGroupname) {
437*3f982cf4SFabien Sanglard     return false;
438*3f982cf4SFabien Sanglard   } else if (node->type == AstNode::Type::kGroup) {
439*3f982cf4SFabien Sanglard     entry->which = CddlGroup::Entry::Which::kGroup;
440*3f982cf4SFabien Sanglard     entry->group = AnalyzeGroup(table, *node);
441*3f982cf4SFabien Sanglard   }
442*3f982cf4SFabien Sanglard   return true;
443*3f982cf4SFabien Sanglard }
444*3f982cf4SFabien Sanglard 
BuildSymbolTable(const AstNode & rules)445*3f982cf4SFabien Sanglard std::pair<bool, CddlSymbolTable> BuildSymbolTable(const AstNode& rules) {
446*3f982cf4SFabien Sanglard   std::pair<bool, CddlSymbolTable> result;
447*3f982cf4SFabien Sanglard   result.first = false;
448*3f982cf4SFabien Sanglard   auto& table = result.second;
449*3f982cf4SFabien Sanglard 
450*3f982cf4SFabien Sanglard   // Parse over all rules iteratively.
451*3f982cf4SFabien Sanglard   for (const AstNode* rule = &rules; rule; rule = rule->sibling) {
452*3f982cf4SFabien Sanglard     AstNode* node = rule->children;
453*3f982cf4SFabien Sanglard 
454*3f982cf4SFabien Sanglard     // Ensure that the node is either a type or group definition.
455*3f982cf4SFabien Sanglard     if (node->type != AstNode::Type::kTypename &&
456*3f982cf4SFabien Sanglard         node->type != AstNode::Type::kGroupname) {
457*3f982cf4SFabien Sanglard       Logger::Error("Error parsing node with text '%s'. Unexpected node type.",
458*3f982cf4SFabien Sanglard                     node->text);
459*3f982cf4SFabien Sanglard       return result;
460*3f982cf4SFabien Sanglard     }
461*3f982cf4SFabien Sanglard     bool is_type = node->type == AstNode::Type::kTypename;
462*3f982cf4SFabien Sanglard     absl::string_view name = node->text;
463*3f982cf4SFabien Sanglard 
464*3f982cf4SFabien Sanglard     // Ensure that the node is assignment.
465*3f982cf4SFabien Sanglard     node = node->sibling;
466*3f982cf4SFabien Sanglard     if (node->type != AstNode::Type::kAssign) {
467*3f982cf4SFabien Sanglard       Logger::Error("Error parsing node with text '%s'. Node type != kAssign.",
468*3f982cf4SFabien Sanglard                     node->text);
469*3f982cf4SFabien Sanglard       return result;
470*3f982cf4SFabien Sanglard     }
471*3f982cf4SFabien Sanglard 
472*3f982cf4SFabien Sanglard     // Process the definition.
473*3f982cf4SFabien Sanglard     node = node->sibling;
474*3f982cf4SFabien Sanglard     if (is_type) {
475*3f982cf4SFabien Sanglard       CddlType* type = AnalyzeType(&table, *node);
476*3f982cf4SFabien Sanglard       if (rule->type_key != absl::nullopt) {
477*3f982cf4SFabien Sanglard         auto parsed_type_key = ParseOptionalUint(rule->type_key.value());
478*3f982cf4SFabien Sanglard         if (parsed_type_key == absl::nullopt) {
479*3f982cf4SFabien Sanglard           return result;
480*3f982cf4SFabien Sanglard         }
481*3f982cf4SFabien Sanglard         type->type_key = parsed_type_key.value();
482*3f982cf4SFabien Sanglard       }
483*3f982cf4SFabien Sanglard       if (!type) {
484*3f982cf4SFabien Sanglard         Logger::Error(
485*3f982cf4SFabien Sanglard             "Error parsing node with text '%s'."
486*3f982cf4SFabien Sanglard             "Failed to analyze node type.",
487*3f982cf4SFabien Sanglard             node->text);
488*3f982cf4SFabien Sanglard       }
489*3f982cf4SFabien Sanglard       table.type_map.emplace(std::string(name), type);
490*3f982cf4SFabien Sanglard     } else {
491*3f982cf4SFabien Sanglard       table.groups.emplace_back(new CddlGroup);
492*3f982cf4SFabien Sanglard       CddlGroup* group = table.groups.back().get();
493*3f982cf4SFabien Sanglard       group->entries.emplace_back(new CddlGroup::Entry);
494*3f982cf4SFabien Sanglard       AnalyzeGroupEntry(&table, *node, group->entries.back().get());
495*3f982cf4SFabien Sanglard       table.group_map.emplace(std::string(name), group);
496*3f982cf4SFabien Sanglard     }
497*3f982cf4SFabien Sanglard   }
498*3f982cf4SFabien Sanglard 
499*3f982cf4SFabien Sanglard   DumpSymbolTable(&result.second);
500*3f982cf4SFabien Sanglard 
501*3f982cf4SFabien Sanglard   result.first = true;
502*3f982cf4SFabien Sanglard   return result;
503*3f982cf4SFabien Sanglard }
504*3f982cf4SFabien Sanglard 
505*3f982cf4SFabien Sanglard // Fetches a C++ Type from all known definitons, or inserts a placeholder to be
506*3f982cf4SFabien Sanglard // updated later if the type hasn't been defined yet.
GetCppType(CppSymbolTable * table,const std::string & name)507*3f982cf4SFabien Sanglard CppType* GetCppType(CppSymbolTable* table, const std::string& name) {
508*3f982cf4SFabien Sanglard   if (name.empty()) {
509*3f982cf4SFabien Sanglard     table->cpp_types.emplace_back(new CppType);
510*3f982cf4SFabien Sanglard     return table->cpp_types.back().get();
511*3f982cf4SFabien Sanglard   }
512*3f982cf4SFabien Sanglard   auto entry = table->cpp_type_map.find(name);
513*3f982cf4SFabien Sanglard   if (entry != table->cpp_type_map.end())
514*3f982cf4SFabien Sanglard     return entry->second;
515*3f982cf4SFabien Sanglard   table->cpp_types.emplace_back(new CppType);
516*3f982cf4SFabien Sanglard   table->cpp_type_map.emplace(name, table->cpp_types.back().get());
517*3f982cf4SFabien Sanglard   return table->cpp_types.back().get();
518*3f982cf4SFabien Sanglard }
519*3f982cf4SFabien Sanglard 
520*3f982cf4SFabien Sanglard bool IncludeGroupMembersInEnum(CppSymbolTable* table,
521*3f982cf4SFabien Sanglard                                const CddlSymbolTable& cddl_table,
522*3f982cf4SFabien Sanglard                                CppType* cpp_type,
523*3f982cf4SFabien Sanglard                                const CddlGroup& group);
524*3f982cf4SFabien Sanglard 
IncludeGroupMembersInSubEnum(CppSymbolTable * table,const CddlSymbolTable & cddl_table,CppType * cpp_type,const std::string & name)525*3f982cf4SFabien Sanglard bool IncludeGroupMembersInSubEnum(CppSymbolTable* table,
526*3f982cf4SFabien Sanglard                                   const CddlSymbolTable& cddl_table,
527*3f982cf4SFabien Sanglard                                   CppType* cpp_type,
528*3f982cf4SFabien Sanglard                                   const std::string& name) {
529*3f982cf4SFabien Sanglard   auto group_entry = cddl_table.group_map.find(name);
530*3f982cf4SFabien Sanglard   if (group_entry == cddl_table.group_map.end()) {
531*3f982cf4SFabien Sanglard     return false;
532*3f982cf4SFabien Sanglard   }
533*3f982cf4SFabien Sanglard   if (group_entry->second->entries.size() != 1 ||
534*3f982cf4SFabien Sanglard       group_entry->second->entries[0]->which !=
535*3f982cf4SFabien Sanglard           CddlGroup::Entry::Which::kGroup) {
536*3f982cf4SFabien Sanglard     return false;
537*3f982cf4SFabien Sanglard   }
538*3f982cf4SFabien Sanglard   CppType* sub_enum = GetCppType(table, name);
539*3f982cf4SFabien Sanglard   if (sub_enum->which == CppType::Which::kUninitialized) {
540*3f982cf4SFabien Sanglard     sub_enum->InitEnum();
541*3f982cf4SFabien Sanglard     sub_enum->name = name;
542*3f982cf4SFabien Sanglard     if (!IncludeGroupMembersInEnum(table, cddl_table, sub_enum,
543*3f982cf4SFabien Sanglard                                    *group_entry->second->entries[0]->group)) {
544*3f982cf4SFabien Sanglard       return false;
545*3f982cf4SFabien Sanglard     }
546*3f982cf4SFabien Sanglard   }
547*3f982cf4SFabien Sanglard   cpp_type->enum_type.sub_members.push_back(sub_enum);
548*3f982cf4SFabien Sanglard   return true;
549*3f982cf4SFabien Sanglard }
550*3f982cf4SFabien Sanglard 
IncludeGroupMembersInEnum(CppSymbolTable * table,const CddlSymbolTable & cddl_table,CppType * cpp_type,const CddlGroup & group)551*3f982cf4SFabien Sanglard bool IncludeGroupMembersInEnum(CppSymbolTable* table,
552*3f982cf4SFabien Sanglard                                const CddlSymbolTable& cddl_table,
553*3f982cf4SFabien Sanglard                                CppType* cpp_type,
554*3f982cf4SFabien Sanglard                                const CddlGroup& group) {
555*3f982cf4SFabien Sanglard   for (const auto& x : group.entries) {
556*3f982cf4SFabien Sanglard     if (x->HasOccurrenceOperator() ||
557*3f982cf4SFabien Sanglard         x->which != CddlGroup::Entry::Which::kType) {
558*3f982cf4SFabien Sanglard       return false;
559*3f982cf4SFabien Sanglard     }
560*3f982cf4SFabien Sanglard     if (x->type.value->which == CddlType::Which::kValue &&
561*3f982cf4SFabien Sanglard         !x->type.opt_key.empty()) {
562*3f982cf4SFabien Sanglard       cpp_type->enum_type.members.emplace_back(
563*3f982cf4SFabien Sanglard           x->type.opt_key, atoi(x->type.value->value.c_str()));
564*3f982cf4SFabien Sanglard     } else if (x->type.value->which == CddlType::Which::kId) {
565*3f982cf4SFabien Sanglard       IncludeGroupMembersInSubEnum(table, cddl_table, cpp_type,
566*3f982cf4SFabien Sanglard                                    x->type.value->id);
567*3f982cf4SFabien Sanglard     } else {
568*3f982cf4SFabien Sanglard       return false;
569*3f982cf4SFabien Sanglard     }
570*3f982cf4SFabien Sanglard   }
571*3f982cf4SFabien Sanglard   return true;
572*3f982cf4SFabien Sanglard }
573*3f982cf4SFabien Sanglard 
574*3f982cf4SFabien Sanglard CppType* MakeCppType(CppSymbolTable* table,
575*3f982cf4SFabien Sanglard                      const CddlSymbolTable& cddl_table,
576*3f982cf4SFabien Sanglard                      const std::string& name,
577*3f982cf4SFabien Sanglard                      const CddlType& type);
578*3f982cf4SFabien Sanglard 
AddMembersToStruct(CppSymbolTable * table,const CddlSymbolTable & cddl_table,CppType * cpp_type,const std::vector<std::unique_ptr<CddlGroup::Entry>> & entries)579*3f982cf4SFabien Sanglard bool AddMembersToStruct(
580*3f982cf4SFabien Sanglard     CppSymbolTable* table,
581*3f982cf4SFabien Sanglard     const CddlSymbolTable& cddl_table,
582*3f982cf4SFabien Sanglard     CppType* cpp_type,
583*3f982cf4SFabien Sanglard     const std::vector<std::unique_ptr<CddlGroup::Entry>>& entries) {
584*3f982cf4SFabien Sanglard   for (const auto& x : entries) {
585*3f982cf4SFabien Sanglard     if (x->which == CddlGroup::Entry::Which::kType) {
586*3f982cf4SFabien Sanglard       if (x->type.opt_key.empty()) {
587*3f982cf4SFabien Sanglard         // If the represented node has no text (ie - it's code generated) then
588*3f982cf4SFabien Sanglard         // it must have an inner type that is based on the user input. If this
589*3f982cf4SFabien Sanglard         // one looks as expected, process it recursively.
590*3f982cf4SFabien Sanglard         if (x->type.value->which != CddlType::Which::kId ||
591*3f982cf4SFabien Sanglard             x->HasOccurrenceOperator()) {
592*3f982cf4SFabien Sanglard           return false;
593*3f982cf4SFabien Sanglard         }
594*3f982cf4SFabien Sanglard         auto group_entry = cddl_table.group_map.find(x->type.value->id);
595*3f982cf4SFabien Sanglard         if (group_entry == cddl_table.group_map.end())
596*3f982cf4SFabien Sanglard           return false;
597*3f982cf4SFabien Sanglard         if (group_entry->second->entries.size() != 1 ||
598*3f982cf4SFabien Sanglard             group_entry->second->entries[0]->which !=
599*3f982cf4SFabien Sanglard                 CddlGroup::Entry::Which::kGroup) {
600*3f982cf4SFabien Sanglard           return false;
601*3f982cf4SFabien Sanglard         }
602*3f982cf4SFabien Sanglard         if (!AddMembersToStruct(
603*3f982cf4SFabien Sanglard                 table, cddl_table, cpp_type,
604*3f982cf4SFabien Sanglard                 group_entry->second->entries[0]->group->entries)) {
605*3f982cf4SFabien Sanglard           return false;
606*3f982cf4SFabien Sanglard         }
607*3f982cf4SFabien Sanglard       } else {
608*3f982cf4SFabien Sanglard         // Here it is a real type definition - so process it as such.
609*3f982cf4SFabien Sanglard         CppType* member_type =
610*3f982cf4SFabien Sanglard             MakeCppType(table, cddl_table,
611*3f982cf4SFabien Sanglard                         cpp_type->name + std::string("_") + x->type.opt_key,
612*3f982cf4SFabien Sanglard                         *x->type.value);
613*3f982cf4SFabien Sanglard         if (!member_type)
614*3f982cf4SFabien Sanglard           return false;
615*3f982cf4SFabien Sanglard         if (member_type->name.empty())
616*3f982cf4SFabien Sanglard           member_type->name = x->type.opt_key;
617*3f982cf4SFabien Sanglard         if (x->opt_occurrence_min ==
618*3f982cf4SFabien Sanglard                 CddlGroup::Entry::kOccurrenceMinUnbounded &&
619*3f982cf4SFabien Sanglard             x->opt_occurrence_max == 1) {
620*3f982cf4SFabien Sanglard           // Create an "optional" type, with sub-type being the type that is
621*3f982cf4SFabien Sanglard           // optional. This corresponds with occurrence operator '?'.
622*3f982cf4SFabien Sanglard           table->cpp_types.emplace_back(new CppType);
623*3f982cf4SFabien Sanglard           CppType* optional_type = table->cpp_types.back().get();
624*3f982cf4SFabien Sanglard           optional_type->which = CppType::Which::kOptional;
625*3f982cf4SFabien Sanglard           optional_type->optional_type = member_type;
626*3f982cf4SFabien Sanglard           cpp_type->struct_type.members.emplace_back(
627*3f982cf4SFabien Sanglard               x->type.opt_key, x->type.integer_key, optional_type);
628*3f982cf4SFabien Sanglard         } else {
629*3f982cf4SFabien Sanglard           cpp_type->struct_type.members.emplace_back(
630*3f982cf4SFabien Sanglard               x->type.opt_key, x->type.integer_key, member_type);
631*3f982cf4SFabien Sanglard         }
632*3f982cf4SFabien Sanglard       }
633*3f982cf4SFabien Sanglard     } else {
634*3f982cf4SFabien Sanglard       // If it's not a type, it's a group so add its members recursuvely.
635*3f982cf4SFabien Sanglard       if (!AddMembersToStruct(table, cddl_table, cpp_type, x->group->entries))
636*3f982cf4SFabien Sanglard         return false;
637*3f982cf4SFabien Sanglard     }
638*3f982cf4SFabien Sanglard   }
639*3f982cf4SFabien Sanglard   return true;
640*3f982cf4SFabien Sanglard }
641*3f982cf4SFabien Sanglard 
MakeCppType(CppSymbolTable * table,const CddlSymbolTable & cddl_table,const std::string & name,const CddlType & type)642*3f982cf4SFabien Sanglard CppType* MakeCppType(CppSymbolTable* table,
643*3f982cf4SFabien Sanglard                      const CddlSymbolTable& cddl_table,
644*3f982cf4SFabien Sanglard                      const std::string& name,
645*3f982cf4SFabien Sanglard                      const CddlType& type) {
646*3f982cf4SFabien Sanglard   CppType* cpp_type = nullptr;
647*3f982cf4SFabien Sanglard   switch (type.which) {
648*3f982cf4SFabien Sanglard     case CddlType::Which::kId: {
649*3f982cf4SFabien Sanglard       if (type.id == "uint") {
650*3f982cf4SFabien Sanglard         cpp_type = GetCppType(table, name);
651*3f982cf4SFabien Sanglard         cpp_type->which = CppType::Which::kUint64;
652*3f982cf4SFabien Sanglard       } else if (type.id == "text") {
653*3f982cf4SFabien Sanglard         cpp_type = GetCppType(table, name);
654*3f982cf4SFabien Sanglard         cpp_type->which = CppType::Which::kString;
655*3f982cf4SFabien Sanglard       } else if (type.id == "bytes") {
656*3f982cf4SFabien Sanglard         cpp_type = GetCppType(table, name);
657*3f982cf4SFabien Sanglard         cpp_type->InitBytes();
658*3f982cf4SFabien Sanglard         if (type.op == CddlType::Op::kSize) {
659*3f982cf4SFabien Sanglard           size_t size = 0;
660*3f982cf4SFabien Sanglard           if (!absl::SimpleAtoi(type.constraint_type->value, &size)) {
661*3f982cf4SFabien Sanglard             return nullptr;
662*3f982cf4SFabien Sanglard           }
663*3f982cf4SFabien Sanglard           cpp_type->bytes_type.fixed_size = size;
664*3f982cf4SFabien Sanglard         }
665*3f982cf4SFabien Sanglard       } else {
666*3f982cf4SFabien Sanglard         cpp_type = GetCppType(table, type.id);
667*3f982cf4SFabien Sanglard       }
668*3f982cf4SFabien Sanglard     } break;
669*3f982cf4SFabien Sanglard     case CddlType::Which::kMap: {
670*3f982cf4SFabien Sanglard       cpp_type = GetCppType(table, name);
671*3f982cf4SFabien Sanglard       cpp_type->InitStruct();
672*3f982cf4SFabien Sanglard       cpp_type->struct_type.key_type = CppType::Struct::KeyType::kMap;
673*3f982cf4SFabien Sanglard       cpp_type->name = name;
674*3f982cf4SFabien Sanglard       if (!AddMembersToStruct(table, cddl_table, cpp_type, type.map->entries))
675*3f982cf4SFabien Sanglard         return nullptr;
676*3f982cf4SFabien Sanglard     } break;
677*3f982cf4SFabien Sanglard     case CddlType::Which::kArray: {
678*3f982cf4SFabien Sanglard       cpp_type = GetCppType(table, name);
679*3f982cf4SFabien Sanglard       if (type.array->entries.size() == 1 &&
680*3f982cf4SFabien Sanglard           type.array->entries[0]->HasOccurrenceOperator()) {
681*3f982cf4SFabien Sanglard         cpp_type->InitVector();
682*3f982cf4SFabien Sanglard         cpp_type->vector_type.min_length =
683*3f982cf4SFabien Sanglard             type.array->entries[0]->opt_occurrence_min;
684*3f982cf4SFabien Sanglard         cpp_type->vector_type.max_length =
685*3f982cf4SFabien Sanglard             type.array->entries[0]->opt_occurrence_max;
686*3f982cf4SFabien Sanglard         cpp_type->vector_type.element_type =
687*3f982cf4SFabien Sanglard             GetCppType(table, type.array->entries[0]->type.value->id);
688*3f982cf4SFabien Sanglard       } else {
689*3f982cf4SFabien Sanglard         cpp_type->InitStruct();
690*3f982cf4SFabien Sanglard         cpp_type->struct_type.key_type = CppType::Struct::KeyType::kArray;
691*3f982cf4SFabien Sanglard         cpp_type->name = name;
692*3f982cf4SFabien Sanglard         if (!AddMembersToStruct(table, cddl_table, cpp_type,
693*3f982cf4SFabien Sanglard                                 type.map->entries)) {
694*3f982cf4SFabien Sanglard           return nullptr;
695*3f982cf4SFabien Sanglard         }
696*3f982cf4SFabien Sanglard       }
697*3f982cf4SFabien Sanglard     } break;
698*3f982cf4SFabien Sanglard     case CddlType::Which::kGroupChoice: {
699*3f982cf4SFabien Sanglard       cpp_type = GetCppType(table, name);
700*3f982cf4SFabien Sanglard       cpp_type->InitEnum();
701*3f982cf4SFabien Sanglard       cpp_type->name = name;
702*3f982cf4SFabien Sanglard       if (!IncludeGroupMembersInEnum(table, cddl_table, cpp_type,
703*3f982cf4SFabien Sanglard                                      *type.group_choice)) {
704*3f982cf4SFabien Sanglard         return nullptr;
705*3f982cf4SFabien Sanglard       }
706*3f982cf4SFabien Sanglard     } break;
707*3f982cf4SFabien Sanglard     case CddlType::Which::kGroupnameChoice: {
708*3f982cf4SFabien Sanglard       cpp_type = GetCppType(table, name);
709*3f982cf4SFabien Sanglard       cpp_type->InitEnum();
710*3f982cf4SFabien Sanglard       cpp_type->name = name;
711*3f982cf4SFabien Sanglard       if (!IncludeGroupMembersInSubEnum(table, cddl_table, cpp_type, type.id)) {
712*3f982cf4SFabien Sanglard         return nullptr;
713*3f982cf4SFabien Sanglard       }
714*3f982cf4SFabien Sanglard     } break;
715*3f982cf4SFabien Sanglard     case CddlType::Which::kDirectChoice: {
716*3f982cf4SFabien Sanglard       cpp_type = GetCppType(table, name);
717*3f982cf4SFabien Sanglard       cpp_type->InitDiscriminatedUnion();
718*3f982cf4SFabien Sanglard       for (const auto* cddl_choice : type.direct_choice) {
719*3f982cf4SFabien Sanglard         CppType* member = MakeCppType(table, cddl_table, "", *cddl_choice);
720*3f982cf4SFabien Sanglard         if (!member)
721*3f982cf4SFabien Sanglard           return nullptr;
722*3f982cf4SFabien Sanglard         cpp_type->discriminated_union.members.push_back(member);
723*3f982cf4SFabien Sanglard       }
724*3f982cf4SFabien Sanglard       return cpp_type;
725*3f982cf4SFabien Sanglard     }
726*3f982cf4SFabien Sanglard     case CddlType::Which::kTaggedType: {
727*3f982cf4SFabien Sanglard       cpp_type = GetCppType(table, name);
728*3f982cf4SFabien Sanglard       cpp_type->which = CppType::Which::kTaggedType;
729*3f982cf4SFabien Sanglard       cpp_type->tagged_type.tag = type.tagged_type.tag_value;
730*3f982cf4SFabien Sanglard       cpp_type->tagged_type.real_type =
731*3f982cf4SFabien Sanglard           MakeCppType(table, cddl_table, "", *type.tagged_type.type);
732*3f982cf4SFabien Sanglard     } break;
733*3f982cf4SFabien Sanglard     default:
734*3f982cf4SFabien Sanglard       return nullptr;
735*3f982cf4SFabien Sanglard   }
736*3f982cf4SFabien Sanglard 
737*3f982cf4SFabien Sanglard   cpp_type->type_key = type.type_key;
738*3f982cf4SFabien Sanglard   return cpp_type;
739*3f982cf4SFabien Sanglard }
740*3f982cf4SFabien Sanglard 
PrePopulateCppTypes(CppSymbolTable * table)741*3f982cf4SFabien Sanglard void PrePopulateCppTypes(CppSymbolTable* table) {
742*3f982cf4SFabien Sanglard   std::vector<std::pair<std::string, CppType::Which>> default_types;
743*3f982cf4SFabien Sanglard   default_types.emplace_back("text", CppType::Which::kString);
744*3f982cf4SFabien Sanglard   default_types.emplace_back("tstr", CppType::Which::kString);
745*3f982cf4SFabien Sanglard   default_types.emplace_back("bstr", CppType::Which::kBytes);
746*3f982cf4SFabien Sanglard   default_types.emplace_back("bytes", CppType::Which::kBytes);
747*3f982cf4SFabien Sanglard   default_types.emplace_back("uint", CppType::Which::kUint64);
748*3f982cf4SFabien Sanglard 
749*3f982cf4SFabien Sanglard   for (auto& pair : default_types) {
750*3f982cf4SFabien Sanglard     auto entry = table->cpp_type_map.find(pair.first);
751*3f982cf4SFabien Sanglard     if (entry != table->cpp_type_map.end())
752*3f982cf4SFabien Sanglard       continue;
753*3f982cf4SFabien Sanglard     table->cpp_types.emplace_back(new CppType);
754*3f982cf4SFabien Sanglard     auto* type = table->cpp_types.back().get();
755*3f982cf4SFabien Sanglard     type->name = pair.first;
756*3f982cf4SFabien Sanglard     type->which = pair.second;
757*3f982cf4SFabien Sanglard     table->cpp_type_map.emplace(pair.first, type);
758*3f982cf4SFabien Sanglard   }
759*3f982cf4SFabien Sanglard }
760*3f982cf4SFabien Sanglard 
BuildCppTypes(const CddlSymbolTable & cddl_table)761*3f982cf4SFabien Sanglard std::pair<bool, CppSymbolTable> BuildCppTypes(
762*3f982cf4SFabien Sanglard     const CddlSymbolTable& cddl_table) {
763*3f982cf4SFabien Sanglard   std::pair<bool, CppSymbolTable> result;
764*3f982cf4SFabien Sanglard   result.first = false;
765*3f982cf4SFabien Sanglard   PrePopulateCppTypes(&result.second);
766*3f982cf4SFabien Sanglard   auto& table = result.second;
767*3f982cf4SFabien Sanglard   for (const auto& type_entry : cddl_table.type_map) {
768*3f982cf4SFabien Sanglard     if (!MakeCppType(&table, cddl_table, type_entry.first,
769*3f982cf4SFabien Sanglard                      *type_entry.second)) {
770*3f982cf4SFabien Sanglard       return result;
771*3f982cf4SFabien Sanglard     }
772*3f982cf4SFabien Sanglard   }
773*3f982cf4SFabien Sanglard 
774*3f982cf4SFabien Sanglard   result.first = true;
775*3f982cf4SFabien Sanglard   return result;
776*3f982cf4SFabien Sanglard }
777*3f982cf4SFabien Sanglard 
VerifyUniqueKeysInMember(std::unordered_set<std::string> * keys,const CppType::Struct::CppMember & member)778*3f982cf4SFabien Sanglard bool VerifyUniqueKeysInMember(std::unordered_set<std::string>* keys,
779*3f982cf4SFabien Sanglard                               const CppType::Struct::CppMember& member) {
780*3f982cf4SFabien Sanglard   return keys->insert(member.name).second &&
781*3f982cf4SFabien Sanglard          (!member.integer_key.has_value() ||
782*3f982cf4SFabien Sanglard           keys->insert(std::to_string(member.integer_key.value())).second);
783*3f982cf4SFabien Sanglard }
784*3f982cf4SFabien Sanglard 
HasUniqueKeys(const CppType & type)785*3f982cf4SFabien Sanglard bool HasUniqueKeys(const CppType& type) {
786*3f982cf4SFabien Sanglard   std::unordered_set<std::string> keys;
787*3f982cf4SFabien Sanglard   return type.which != CppType::Which::kStruct ||
788*3f982cf4SFabien Sanglard          absl::c_all_of(type.struct_type.members,
789*3f982cf4SFabien Sanglard                         [&keys](const CppType::Struct::CppMember& member) {
790*3f982cf4SFabien Sanglard                           return VerifyUniqueKeysInMember(&keys, member);
791*3f982cf4SFabien Sanglard                         });
792*3f982cf4SFabien Sanglard }
793*3f982cf4SFabien Sanglard 
IsUniqueEnumValue(std::vector<uint64_t> * values,uint64_t v)794*3f982cf4SFabien Sanglard bool IsUniqueEnumValue(std::vector<uint64_t>* values, uint64_t v) {
795*3f982cf4SFabien Sanglard   auto it = std::lower_bound(values->begin(), values->end(), v);
796*3f982cf4SFabien Sanglard   if (it == values->end() || *it != v) {
797*3f982cf4SFabien Sanglard     values->insert(it, v);
798*3f982cf4SFabien Sanglard     return true;
799*3f982cf4SFabien Sanglard   }
800*3f982cf4SFabien Sanglard   return false;
801*3f982cf4SFabien Sanglard }
802*3f982cf4SFabien Sanglard 
HasUniqueEnumValues(std::vector<uint64_t> * values,const CppType & type)803*3f982cf4SFabien Sanglard bool HasUniqueEnumValues(std::vector<uint64_t>* values, const CppType& type) {
804*3f982cf4SFabien Sanglard   return absl::c_all_of(type.enum_type.sub_members,
805*3f982cf4SFabien Sanglard                         [values](CppType* sub_member) {
806*3f982cf4SFabien Sanglard                           return HasUniqueEnumValues(values, *sub_member);
807*3f982cf4SFabien Sanglard                         }) &&
808*3f982cf4SFabien Sanglard          absl::c_all_of(
809*3f982cf4SFabien Sanglard              type.enum_type.members,
810*3f982cf4SFabien Sanglard              [values](const std::pair<std::string, uint64_t>& member) {
811*3f982cf4SFabien Sanglard                return IsUniqueEnumValue(values, member.second);
812*3f982cf4SFabien Sanglard              });
813*3f982cf4SFabien Sanglard }
814*3f982cf4SFabien Sanglard 
HasUniqueEnumValues(const CppType & type)815*3f982cf4SFabien Sanglard bool HasUniqueEnumValues(const CppType& type) {
816*3f982cf4SFabien Sanglard   std::vector<uint64_t> values;
817*3f982cf4SFabien Sanglard   return type.which != CppType::Which::kEnum ||
818*3f982cf4SFabien Sanglard          HasUniqueEnumValues(&values, type);
819*3f982cf4SFabien Sanglard }
820*3f982cf4SFabien Sanglard 
ValidateCppTypes(const CppSymbolTable & cpp_symbols)821*3f982cf4SFabien Sanglard bool ValidateCppTypes(const CppSymbolTable& cpp_symbols) {
822*3f982cf4SFabien Sanglard   return absl::c_all_of(
823*3f982cf4SFabien Sanglard       cpp_symbols.cpp_types, [](const std::unique_ptr<CppType>& ptr) {
824*3f982cf4SFabien Sanglard         return HasUniqueKeys(*ptr) && HasUniqueEnumValues(*ptr);
825*3f982cf4SFabien Sanglard       });
826*3f982cf4SFabien Sanglard }
827*3f982cf4SFabien Sanglard 
DumpTypeKey(absl::optional<uint64_t> key)828*3f982cf4SFabien Sanglard std::string DumpTypeKey(absl::optional<uint64_t> key) {
829*3f982cf4SFabien Sanglard   if (key != absl::nullopt) {
830*3f982cf4SFabien Sanglard     return " (type key=\"" + std::to_string(key.value()) + "\")";
831*3f982cf4SFabien Sanglard   }
832*3f982cf4SFabien Sanglard   return "";
833*3f982cf4SFabien Sanglard }
834*3f982cf4SFabien Sanglard 
DumpType(CddlType * type,int indent_level)835*3f982cf4SFabien Sanglard void DumpType(CddlType* type, int indent_level) {
836*3f982cf4SFabien Sanglard   std::string output = "";
837*3f982cf4SFabien Sanglard   for (int i = 0; i <= indent_level; ++i)
838*3f982cf4SFabien Sanglard     output += "--";
839*3f982cf4SFabien Sanglard   switch (type->which) {
840*3f982cf4SFabien Sanglard     case CddlType::Which::kDirectChoice:
841*3f982cf4SFabien Sanglard       output = "kDirectChoice" + DumpTypeKey(type->type_key) + ": ";
842*3f982cf4SFabien Sanglard       Logger::Log(output);
843*3f982cf4SFabien Sanglard       for (auto& option : type->direct_choice)
844*3f982cf4SFabien Sanglard         DumpType(option, indent_level + 1);
845*3f982cf4SFabien Sanglard       break;
846*3f982cf4SFabien Sanglard     case CddlType::Which::kValue:
847*3f982cf4SFabien Sanglard       output += "kValue" + DumpTypeKey(type->type_key) + ": " + type->value;
848*3f982cf4SFabien Sanglard       Logger::Log(output);
849*3f982cf4SFabien Sanglard       break;
850*3f982cf4SFabien Sanglard     case CddlType::Which::kId:
851*3f982cf4SFabien Sanglard       output += "kId" + DumpTypeKey(type->type_key) + ": " + type->id;
852*3f982cf4SFabien Sanglard       Logger::Log(output);
853*3f982cf4SFabien Sanglard       break;
854*3f982cf4SFabien Sanglard     case CddlType::Which::kMap:
855*3f982cf4SFabien Sanglard       output += "kMap" + DumpTypeKey(type->type_key) + ": ";
856*3f982cf4SFabien Sanglard       Logger::Log(output);
857*3f982cf4SFabien Sanglard       DumpGroup(type->map, indent_level + 1);
858*3f982cf4SFabien Sanglard       break;
859*3f982cf4SFabien Sanglard     case CddlType::Which::kArray:
860*3f982cf4SFabien Sanglard       output += "kArray" + DumpTypeKey(type->type_key) + ": ";
861*3f982cf4SFabien Sanglard       Logger::Log(output);
862*3f982cf4SFabien Sanglard       DumpGroup(type->array, indent_level + 1);
863*3f982cf4SFabien Sanglard       break;
864*3f982cf4SFabien Sanglard     case CddlType::Which::kGroupChoice:
865*3f982cf4SFabien Sanglard       output += "kGroupChoice" + DumpTypeKey(type->type_key) + ": ";
866*3f982cf4SFabien Sanglard       Logger::Log(output);
867*3f982cf4SFabien Sanglard       DumpGroup(type->group_choice, indent_level + 1);
868*3f982cf4SFabien Sanglard       break;
869*3f982cf4SFabien Sanglard     case CddlType::Which::kGroupnameChoice:
870*3f982cf4SFabien Sanglard       output += "kGroupnameChoice" + DumpTypeKey(type->type_key) + ": ";
871*3f982cf4SFabien Sanglard       Logger::Log(output);
872*3f982cf4SFabien Sanglard       break;
873*3f982cf4SFabien Sanglard     case CddlType::Which::kTaggedType:
874*3f982cf4SFabien Sanglard       output += "kTaggedType" + DumpTypeKey(type->type_key) + ": " +
875*3f982cf4SFabien Sanglard                 std::to_string(type->tagged_type.tag_value);
876*3f982cf4SFabien Sanglard       Logger::Log(output);
877*3f982cf4SFabien Sanglard       DumpType(type->tagged_type.type, indent_level + 1);
878*3f982cf4SFabien Sanglard       break;
879*3f982cf4SFabien Sanglard   }
880*3f982cf4SFabien Sanglard }
881*3f982cf4SFabien Sanglard 
DumpGroup(CddlGroup * group,int indent_level)882*3f982cf4SFabien Sanglard void DumpGroup(CddlGroup* group, int indent_level) {
883*3f982cf4SFabien Sanglard   for (auto& entry : group->entries) {
884*3f982cf4SFabien Sanglard     std::string output = "";
885*3f982cf4SFabien Sanglard     for (int i = 0; i <= indent_level; ++i)
886*3f982cf4SFabien Sanglard       output += "--";
887*3f982cf4SFabien Sanglard     switch (entry->which) {
888*3f982cf4SFabien Sanglard       case CddlGroup::Entry::Which::kUninitialized:
889*3f982cf4SFabien Sanglard         break;
890*3f982cf4SFabien Sanglard       case CddlGroup::Entry::Which::kType:
891*3f982cf4SFabien Sanglard         output += "kType:";
892*3f982cf4SFabien Sanglard         if (entry->HasOccurrenceOperator()) {
893*3f982cf4SFabien Sanglard           output +=
894*3f982cf4SFabien Sanglard               "minOccurance: " + std::to_string(entry->opt_occurrence_min) +
895*3f982cf4SFabien Sanglard               " maxOccurance: " + std::to_string(entry->opt_occurrence_max);
896*3f982cf4SFabien Sanglard         }
897*3f982cf4SFabien Sanglard         if (!entry->type.opt_key.empty()) {
898*3f982cf4SFabien Sanglard           output += " " + entry->type.opt_key + "=>";
899*3f982cf4SFabien Sanglard         }
900*3f982cf4SFabien Sanglard         Logger::Log(output);
901*3f982cf4SFabien Sanglard         DumpType(entry->type.value, indent_level + 1);
902*3f982cf4SFabien Sanglard         break;
903*3f982cf4SFabien Sanglard       case CddlGroup::Entry::Which::kGroup:
904*3f982cf4SFabien Sanglard         if (entry->HasOccurrenceOperator())
905*3f982cf4SFabien Sanglard           output +=
906*3f982cf4SFabien Sanglard               "minOccurance: " + std::to_string(entry->opt_occurrence_min) +
907*3f982cf4SFabien Sanglard               " maxOccurance: " + std::to_string(entry->opt_occurrence_max);
908*3f982cf4SFabien Sanglard         Logger::Log(output);
909*3f982cf4SFabien Sanglard         DumpGroup(entry->group, indent_level + 1);
910*3f982cf4SFabien Sanglard         break;
911*3f982cf4SFabien Sanglard     }
912*3f982cf4SFabien Sanglard   }
913*3f982cf4SFabien Sanglard }
914*3f982cf4SFabien Sanglard 
DumpSymbolTable(CddlSymbolTable * table)915*3f982cf4SFabien Sanglard void DumpSymbolTable(CddlSymbolTable* table) {
916*3f982cf4SFabien Sanglard   for (auto& entry : table->type_map) {
917*3f982cf4SFabien Sanglard     Logger::Log(entry.first);
918*3f982cf4SFabien Sanglard     DumpType(entry.second);
919*3f982cf4SFabien Sanglard   }
920*3f982cf4SFabien Sanglard   for (auto& entry : table->group_map) {
921*3f982cf4SFabien Sanglard     Logger::Log(entry.first);
922*3f982cf4SFabien Sanglard     DumpGroup(entry.second);
923*3f982cf4SFabien Sanglard   }
924*3f982cf4SFabien Sanglard }
925