1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <sngcm/ast/Enumeration.hpp>
  7 #include <sngcm/ast/Identifier.hpp>
  8 #include <sngcm/ast/Visitor.hpp>
  9 #include <sngcm/ast/AstWriter.hpp>
 10 #include <sngcm/ast/AstReader.hpp>
 11 #include <sngcm/ast/Literal.hpp>
 12 #include <sngcm/ast/Expression.hpp>
 13 
 14 namespace sngcm { namespace ast {
 15 
 16 EnumTypeNode::EnumTypeNode(const Span& span_const boost::uuids::uuid& moduleId_) : Node(NodeType::enumTypeNodespan_moduleId_)
 17 {
 18 }
 19 
 20 EnumTypeNode::EnumTypeNode(const Span& span_const boost::uuids::uuid& moduleId_Specifiers specifiers_IdentifierNode* id_) :
 21     Node(NodeType::enumTypeNodespan_moduleId_)specifiers(specifiers_)id(id_)
 22 {
 23     id->SetParent(this);
 24 }
 25 
 26 Node* EnumTypeNode::Clone(CloneContext& cloneContext) const
 27 {
 28     EnumTypeNode* clone = new EnumTypeNode(GetSpan()ModuleId()specifiersstatic_cast<IdentifierNode*>(id->Clone(cloneContext)));
 29     int n = constants.Count();
 30     for (int i = 0; i < n; ++i)
 31     {
 32         clone->AddConstant(static_cast<EnumConstantNode*>(constants[i]->Clone(cloneContext)));
 33     }
 34     clone->SetBeginBraceSpan(beginBraceSpan);
 35     clone->SetEndBraceSpan(endBraceSpan);
 36     return clone;
 37 }
 38 
 39 void EnumTypeNode::Accept(Visitor& visitor)
 40 {
 41     visitor.Visit(*this);
 42 }
 43 
 44 void EnumTypeNode::Write(AstWriter& writer)
 45 {
 46     Node::Write(writer);
 47     writer.Write(specifiers);
 48     writer.Write(id.get());
 49     bool hasUnderlyingType = underlyingType != nullptr;
 50     writer.GetBinaryWriter().Write(hasUnderlyingType);
 51     if (hasUnderlyingType)
 52     {
 53         writer.Write(underlyingType.get());
 54     }
 55     constants.Write(writer);
 56     bool convertExternal = ModuleId() == writer.SpanConversionModuleId();
 57     writer.Write(beginBraceSpanconvertExternal);
 58     writer.Write(endBraceSpanconvertExternal);
 59 }
 60 
 61 void EnumTypeNode::Read(AstReader& reader)
 62 {
 63     Node::Read(reader);
 64     specifiers = reader.ReadSpecifiers();
 65     id.reset(reader.ReadIdentifierNode());
 66     bool hasUnderlyingType = reader.GetBinaryReader().ReadBool();
 67     if (hasUnderlyingType)
 68     {
 69         underlyingType.reset(reader.ReadNode());
 70     }
 71     constants.Read(reader);
 72     constants.SetParent(this);
 73     beginBraceSpan = reader.ReadSpan();
 74     endBraceSpan = reader.ReadSpan();
 75 }
 76 void EnumTypeNode::AddConstant(EnumConstantNode* constant)
 77 {
 78     constant->SetParent(this);
 79     constants.Add(constant);
 80 }
 81 
 82 EnumConstantNode* EnumTypeNode::GetLastConstant() const
 83 {
 84     int n = constants.Count();
 85     if (n > 0)
 86     {
 87         return constants[n - 1];
 88     }
 89     return nullptr;
 90 }
 91 
 92 void EnumTypeNode::SetUnderlyingType(Node* underlyingType_)
 93 {
 94     underlyingType.reset(underlyingType_);
 95     underlyingType->SetParent(this);
 96 }
 97 
 98 EnumConstantNode::EnumConstantNode(const Span& span_const boost::uuids::uuid& moduleId_) :
 99     Node(NodeType::enumConstantNodespan_moduleId_)hasValue(false)
100 {
101 }
102 
103 EnumConstantNode::EnumConstantNode(const Span& span_const boost::uuids::uuid& moduleId_IdentifierNode* id_Node* value_) :
104     Node(NodeType::enumConstantNodespan_moduleId_)id(id_)value(value_)hasValue(false)
105 {
106     id->SetParent(this);
107     if (value)
108     {
109         value->SetParent(this);
110     }
111 }
112 
113 Node* EnumConstantNode::Clone(CloneContext& cloneContext) const
114 {
115     EnumConstantNode* clone = new EnumConstantNode(GetSpan()ModuleId()static_cast<IdentifierNode*>(id->Clone(cloneContext))value->Clone(cloneContext));
116     if (hasValue)
117     {
118         clone->SetHasValue();
119     }
120     return clone;
121 }
122 
123 void EnumConstantNode::Accept(Visitor& visitor)
124 {
125     visitor.Visit(*this);
126 }
127 
128 void EnumConstantNode::Write(AstWriter& writer)
129 {
130     Node::Write(writer);
131     writer.Write(id.get());
132     writer.Write(value.get());
133     writer.GetBinaryWriter().Write(hasValue);
134     writer.GetBinaryWriter().Write(strValue);
135 }
136 
137 void EnumConstantNode::Read(AstReader& reader)
138 {
139     Node::Read(reader);
140     id.reset(reader.ReadIdentifierNode());
141     id->SetParent(this);
142     value.reset(reader.ReadNode());
143     value->SetParent(this);
144     hasValue = reader.GetBinaryReader().ReadBool();
145     strValue = reader.GetBinaryReader().ReadUtf32String();
146 }
147 
148 Node* MakeNextEnumConstantValue(const Span& spanconst boost::uuids::uuid& moduleIdEnumTypeNode* enumType)
149 {
150     EnumConstantNode* lastConstant = enumType->GetLastConstant();
151     if (lastConstant)
152     {
153         Node* lastValue = lastConstant->GetValue();
154         if (lastValue)
155         {
156             CloneContext cloneContext;
157             Node* clonedValue = lastValue->Clone(cloneContext);
158             if (enumType->GetUnderlyingType())
159             {
160                 if (enumType->GetUnderlyingType()->IsUnsignedTypeNode())
161                 {
162                     return new AddNode(spanmoduleIdclonedValuenew ByteLiteralNode(spanmoduleId1u));
163                 }
164             }
165             return new AddNode(spanmoduleIdclonedValuenew SByteLiteralNode(spanmoduleId1));
166         }
167         else
168         {
169             throw std::runtime_error("last constant returned null value");
170         }
171     }
172     else
173     {
174         if (enumType->GetUnderlyingType())
175         {
176             if (enumType->GetUnderlyingType()->IsUnsignedTypeNode())
177             {
178                 return new ByteLiteralNode(spanmoduleId0u);
179             }
180         }
181         return new SByteLiteralNode(spanmoduleId0);
182     }
183 }
184 
185 } } // namespace sngcm::ast