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