1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <sngcm/ast/CompileUnit.hpp>
  7 #include <sngcm/ast/Identifier.hpp>
  8 #include <sngcm/ast/Visitor.hpp>
  9 #include <sngcm/ast/Namespace.hpp>
 10 #include <sngcm/ast/Class.hpp>
 11 #include <soulng/util/Path.hpp>
 12 #include <soulng/util/Sha1.hpp>
 13 #include <algorithm>
 14 
 15 namespace sngcm { namespace ast {
 16 
 17 CompileUnitNode::CompileUnitNode(const Span& span_const boost::uuids::uuid& moduleId_) : Node(NodeType::compileUnitNodespan_moduleId_)globalNs()isSynthesizedUnit(false)isProgramMainUnit(false)
 18 {
 19 }
 20 
 21 CompileUnitNode::CompileUnitNode(const Span& span_const boost::uuids::uuid& moduleId_const std::string& filePath_) :
 22     Node(NodeType::compileUnitNodespan_moduleId_)filePath(filePath_)globalNs(new NamespaceNode(span_moduleId_new IdentifierNode(span_moduleId_U"")))isSynthesizedUnit(false)isProgramMainUnit(false)
 23 {
 24 }
 25 
 26 Node* CompileUnitNode::Clone(CloneContext& cloneContext) const
 27 {
 28     CompileUnitNode* clone = new CompileUnitNode(GetSpan()ModuleId()filePath);
 29     clone->globalNs.reset(static_cast<NamespaceNode*>(globalNs->Clone(cloneContext)));
 30     return clone;
 31 }
 32 
 33 void CompileUnitNode::Accept(Visitor& visitor)
 34 {
 35     visitor.Visit(*this);
 36 }
 37 
 38 void CompileUnitNode::ResetGlobalNs(NamespaceNode* ns)
 39 {
 40     globalNs.reset(ns);
 41 }
 42 
 43 void CompileUnitNode::ComputeLineStarts(const std::u32string& sourceFileContent)
 44 {
 45     int32_t index = 0;
 46     bool startOfLine = true;
 47     for (const char32_t& c : sourceFileContent)
 48     {
 49         if (startOfLine)
 50         {
 51             lineStarts.push_back(index);
 52             startOfLine = false;
 53         }
 54         if (c == U'\n')
 55         {
 56             startOfLine = true;
 57         }
 58         ++index;
 59     }
 60 }
 61 
 62 int CompileUnitNode::GetColumn(const Span& span) const
 63 {
 64     if (span.Valid())
 65     {
 66         int32_t pos = span.start;
 67         auto it = std::lower_bound(lineStarts.cbegin()lineStarts.cend()pos);
 68         if (it != lineStarts.cend())
 69         {
 70             int32_t start = *it;
 71             if (start != pos && it != lineStarts.cbegin())
 72             {
 73                 --it;
 74                 start = *it;
 75             }
 76             int column = 1 + pos - start;
 77             return column;
 78         }
 79     }
 80     return 1;
 81 }
 82 
 83 const std::string& CompileUnitNode::Id()
 84 {
 85     if (id.empty())
 86     {
 87         std::string baseName = Path::GetFileNameWithoutExtension(filePath);
 88         for (char& c : baseName)
 89         {
 90             if (!std::isalnum(c))
 91             {
 92                 c = '_';
 93             }
 94         }
 95         id = baseName + "_" + GetSha1MessageDigest(filePath);
 96     }
 97     return id;
 98 }
 99 
100 class NamespaceCombiner public Visitor
101 {
102 public:
103     void Visit(CompileUnitNode& compileUnitNode) override;
104     void Visit(NamespaceNode& namespaceNode) override;
105 };
106 
107 void NamespaceCombiner::Visit(CompileUnitNode& compileUnitNode)
108 {
109     compileUnitNode.GlobalNs()->Accept(*this);
110 }
111 
112 void NamespaceCombiner::Visit(NamespaceNode& namespaceNode)
113 {
114     int n = namespaceNode.Members().Count();
115     for (int i = 0; i < n; ++i)
116     {
117         namespaceNode.Members()[i]->Accept(*this);
118     }
119     if (n == 1 && !namespaceNode.Id()->Str().empty())
120     {
121         Node* node = namespaceNode.Members()[0];
122         if (node->GetNodeType() == NodeType::namespaceNode)
123         {
124             std::unique_ptr<NamespaceNode> childNs(static_cast<NamespaceNode*>(namespaceNode.Members().Release(0)));
125             namespaceNode.Id()->SetStr(namespaceNode.Id()->Str() + U"." + childNs->Id()->Str());
126             namespaceNode.Members().Clear();
127             namespaceNode.Members().SetContent(childNs->Members().Content());
128             namespaceNode.Members().SetParent(&namespaceNode);
129         }
130     }
131 }
132 
133 void CombineNamespaces(CompileUnitNode& cu)
134 {
135     NamespaceCombiner combiner;
136     cu.Accept(combiner);
137 }
138 
139 class ClassMemberArranger public Visitor
140 {
141 public:
142     void Visit(CompileUnitNode& compileUnitNode) override;
143     void Visit(NamespaceNode& namespaceNode) override;
144     void Visit(ClassNode& classNode) override;
145 };
146 
147 void ClassMemberArranger::Visit(CompileUnitNode& compileUnitNode)
148 {
149     compileUnitNode.GlobalNs()->Accept(*this);
150 }
151 
152 void ClassMemberArranger::Visit(NamespaceNode& namespaceNode)
153 {
154     int n = namespaceNode.Members().Count();
155     for (int i = 0; i < n; ++i)
156     {
157         namespaceNode.Members()[i]->Accept(*this);
158     }
159 }
160 
161 void ClassMemberArranger::Visit(ClassNode& classNode)
162 {
163     int n = classNode.Members().Count();
164     for (int i = 0; i < n; ++i)
165     {
166         classNode.Members()[i]->Accept(*this);
167     }
168     classNode.ArrangeMembers();
169 }
170 
171 void ArrangeClassMembers(CompileUnitNode& cu)
172 {
173     ClassMemberArranger arranger;
174     cu.Accept(arranger);
175 }
176 
177 class UnnamedNamespaceProcessor public Visitor
178 {
179 public:
180     UnnamedNamespaceProcessor();
181     void Visit(CompileUnitNode& compileUnitNode) override;
182     void Visit(NamespaceNode& namespaceNode) override;
183 private:
184     std::vector<NamespaceNode*> unnamedNamespaces;
185 };
186 
187 UnnamedNamespaceProcessor::UnnamedNamespaceProcessor()
188 {
189 }
190 
191 void UnnamedNamespaceProcessor::Visit(CompileUnitNode& compileUnitNode)
192 {
193     compileUnitNode.GlobalNs()->Accept(*this);
194     int index = 0;
195     for (NamespaceNode* unnamedNs : unnamedNamespaces)
196     {
197         CloneContext cloneContext;
198         IdentifierNode* unnamedNsId = static_cast<IdentifierNode*>(unnamedNs->Id()->Clone(cloneContext));
199         NamespaceImportNode* import = new NamespaceImportNode(compileUnitNode.GetSpan()compileUnitNode.ModuleId()unnamedNsId);
200         compileUnitNode.GlobalNs()->Members().Insert(indeximport);
201         ++index;
202     }
203 }
204 
205 void UnnamedNamespaceProcessor::Visit(NamespaceNode& namespaceNode)
206 {
207     if (namespaceNode.IsUnnamedNs())
208     {
209         unnamedNamespaces.push_back(&namespaceNode);
210     }
211     int n = namespaceNode.Members().Count();
212     for (int i = 0; i < n; ++i)
213     {
214         namespaceNode.Members()[i]->Accept(*this);
215     }
216 }
217 
218 void AddNamespaceImportsForUnnamedNamespaces(CompileUnitNode& cu)
219 {
220     UnnamedNamespaceProcessor processor;
221     cu.Accept(processor);
222 }
223 
224 } } // namespace sngcm::ast