1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <cmajor/binder/BoundConstraint.hpp>
  7 #include <cmajor/binder/BoundNodeVisitor.hpp>
  8 #include <cmajor/symbols/Exception.hpp>
  9 
 10 namespace cmajor { namespace binder {
 11 
 12 BoundConstraint::BoundConstraint(const Span& span_const boost::uuids::uuid& moduleId_BoundNodeType boundNodeType_) : BoundNode(span_moduleId_boundNodeType_)
 13 {
 14 }
 15 
 16 void BoundConstraint::Load(Emitter& emitterOperationFlags flags)
 17 {
 18     throw Exception("cannot load constraint"GetSpan()ModuleId());
 19 }
 20 
 21 void BoundConstraint::Store(Emitter& emitterOperationFlags flags)
 22 {
 23     throw Exception("cannot store constraint"GetSpan()ModuleId());
 24 }
 25 
 26 BoundAtomicConstraint::BoundAtomicConstraint(const Span& span_const boost::uuids::uuid& moduleId_bool satisfied_) :
 27     BoundConstraint(span_moduleId_BoundNodeType::boundAtomicConstraint)satisfied(satisfied_)conceptSymbol(nullptr)
 28 {
 29 }
 30 
 31 void BoundAtomicConstraint::Accept(BoundNodeVisitor& visitor)
 32 {
 33     visitor.Visit(*this);
 34 }
 35 
 36 bool BoundAtomicConstraint::Subsume(BoundConstraint* that) const
 37 {
 38     if (that->IsBinaryConstraint())
 39     {
 40         BoundBinaryConstraint* thatBinaryConstraint = static_cast<BoundBinaryConstraint*>(that);
 41         BoundConstraint* thatLeft = thatBinaryConstraint->Left();
 42         BoundConstraint* thatRight = thatBinaryConstraint->Right();
 43         bool subsumeLeft = Subsume(thatLeft);
 44         bool subsumeRight = Subsume(thatRight);
 45         if (that->GetBoundNodeType() == BoundNodeType::boundConjunctiveConstraint)
 46         {
 47             return subsumeLeft && subsumeRight;
 48         }
 49         else if (that->GetBoundNodeType() == BoundNodeType::boundDisjunctiveConstraint)
 50         {
 51             return subsumeLeft || subsumeRight;
 52         }
 53         else
 54         {
 55             Assert(false"unknown binary constraint type");
 56             return false;
 57         }
 58     }
 59     else if (that->GetBoundNodeType() == BoundNodeType::boundAtomicConstraint)
 60     {
 61         BoundAtomicConstraint* thatAtomic = static_cast<BoundAtomicConstraint*>(that);
 62         if (satisfied && !thatAtomic->Satisfied())
 63         {
 64             return true;
 65         }
 66         else if (!satisfied && thatAtomic->Satisfied())
 67         {
 68             return false;
 69         }
 70         else
 71         {
 72             if (conceptSymbol && !thatAtomic->conceptSymbol)
 73             {
 74                 return true;
 75             }
 76             else if (!conceptSymbol && thatAtomic->conceptSymbol)
 77             {
 78                 return false;
 79             }
 80             else if (!conceptSymbol && !thatAtomic->conceptSymbol)
 81             {
 82                 return true;
 83             }
 84             else
 85             {
 86                 if (conceptSymbol == thatAtomic->conceptSymbol)
 87                 {
 88                     return true;
 89                 }
 90                 ConceptSymbol* refinedConcept = conceptSymbol->RefinedConcept();
 91                 while (refinedConcept)
 92                 {
 93                     if (refinedConcept == thatAtomic->conceptSymbol)
 94                     {
 95                         return true;
 96                     }
 97                     else
 98                     {
 99                         refinedConcept = refinedConcept->RefinedConcept();
100                     }
101                 }
102                 return false;
103             }
104         }
105     }
106     else
107     {
108         return false;
109     }
110 }
111 
112 BoundConstraint* BoundAtomicConstraint::Clone() const
113 {
114     return new BoundAtomicConstraint(*this);
115 }
116 
117 BoundBinaryConstraint::BoundBinaryConstraint(const Span& span_const boost::uuids::uuid& moduleId_BoundNodeType boundNodeType_BoundConstraint* left_BoundConstraint* right_) :
118     BoundConstraint(span_moduleId_boundNodeType_)left(left_)right(right_)
119 {
120 }
121 
122 BoundBinaryConstraint::BoundBinaryConstraint(const BoundBinaryConstraint& that) : BoundConstraint(that)left(that.left->Clone())right(that.right->Clone())
123 {
124 }
125 
126 BoundDisjunctiveConstraint::BoundDisjunctiveConstraint(const Span& span_const boost::uuids::uuid& moduleId_BoundConstraint* left_BoundConstraint* right_) :
127     BoundBinaryConstraint(span_moduleId_BoundNodeType::boundDisjunctiveConstraintleft_right_)
128 {
129 }
130 
131 BoundDisjunctiveConstraint::BoundDisjunctiveConstraint(const BoundDisjunctiveConstraint& that) : BoundBinaryConstraint(that)
132 {
133 }
134 
135 bool BoundDisjunctiveConstraint::Subsume(BoundConstraint* that) const
136 {
137     BoundConstraint* left = Left();
138     BoundConstraint* right = Right();
139     if (that->IsBinaryConstraint())
140     {
141         BoundBinaryConstraint* thatBinaryConstraint = static_cast<BoundBinaryConstraint*>(that);
142         BoundConstraint* thatLeft = thatBinaryConstraint->Left();
143         BoundConstraint* thatRight = thatBinaryConstraint->Right();
144         bool leftSubsumeThatLeft = left->Subsume(thatLeft);
145         bool leftSubsumeThatRight = left->Subsume(thatRight);
146         bool rightSubsumeThatLeft = right->Subsume(thatLeft);
147         bool rightSubsumeThatRight = right->Subsume(thatRight);
148         bool leftSubsumeThatLeftOrThatRight = leftSubsumeThatLeft || leftSubsumeThatRight;
149         bool rightSubsumeThatLeftOrThatRight = rightSubsumeThatLeft || rightSubsumeThatRight;
150         if (that->GetBoundNodeType() == BoundNodeType::boundConjunctiveConstraint)
151         {
152             return leftSubsumeThatLeftOrThatRight && rightSubsumeThatLeftOrThatRight;
153         }
154         else if (that->GetBoundNodeType() == BoundNodeType::boundDisjunctiveConstraint)
155         {
156             return leftSubsumeThatLeftOrThatRight || rightSubsumeThatLeftOrThatRight;
157         }
158         else
159         {
160             Assert(false"unknown binary constraint type");
161             return false;
162         }
163     }
164     else
165     {
166         bool leftSubsumeThat = left->Subsume(that);
167         bool rightSubsumeThat = right->Subsume(that);
168         return leftSubsumeThat && rightSubsumeThat;
169     }
170 }
171 
172 void BoundDisjunctiveConstraint::Accept(BoundNodeVisitor& visitor)
173 {
174     visitor.Visit(*this);
175 }
176 
177 BoundConstraint* BoundDisjunctiveConstraint::Clone() const
178 {
179     return new BoundDisjunctiveConstraint(*this);
180 }
181 
182 BoundConjunctiveConstraint::BoundConjunctiveConstraint(const Span& span_const boost::uuids::uuid& moduleId_BoundConstraint* left_BoundConstraint* right_) :
183     BoundBinaryConstraint(span_moduleId_BoundNodeType::boundConjunctiveConstraintleft_right_)
184 {
185 }
186 
187 BoundConjunctiveConstraint::BoundConjunctiveConstraint(const BoundConjunctiveConstraint& that) : BoundBinaryConstraint(that)
188 {
189 }
190 
191 bool BoundConjunctiveConstraint::Subsume(BoundConstraint* that) const
192 {
193     BoundConstraint* left = Left();
194     BoundConstraint* right = Right();
195     if (that->IsBinaryConstraint())
196     {
197         BoundBinaryConstraint* thatBinaryConstraint = static_cast<BoundBinaryConstraint*>(that);
198         BoundConstraint* thatLeft = thatBinaryConstraint->Left();
199         BoundConstraint* thatRight = thatBinaryConstraint->Right();
200         bool leftSubsumeThatLeft = left->Subsume(thatLeft);
201         bool rightSubsumeThatLeft = right->Subsume(thatLeft);
202         bool leftSubsumeThatRight = left->Subsume(thatRight);
203         bool rightSubsumeThatRight = right->Subsume(thatRight);
204         bool leftOrRightSubsumeThatLeft = leftSubsumeThatLeft || rightSubsumeThatLeft;
205         bool leftOrRightSubsumeThatRight = leftSubsumeThatRight || rightSubsumeThatRight;
206         if (that->GetBoundNodeType() == BoundNodeType::boundConjunctiveConstraint)
207         {
208             return leftOrRightSubsumeThatLeft && leftOrRightSubsumeThatRight;
209         }
210         else if (that->GetBoundNodeType() == BoundNodeType::boundDisjunctiveConstraint)
211         {
212             return leftOrRightSubsumeThatLeft || leftOrRightSubsumeThatRight;
213         }
214         else
215         {
216             Assert(false"unknown binary constraint type");
217             return false;
218         }
219     }
220     else
221     {
222         bool leftSubsumeThat = left->Subsume(that);
223         bool righSubsumeThat = right->Subsume(that);
224         return leftSubsumeThat || righSubsumeThat;
225     }
226 }
227 
228 void BoundConjunctiveConstraint::Accept(BoundNodeVisitor& visitor)
229 {
230     visitor.Visit(*this);
231 }
232 
233 BoundConstraint* BoundConjunctiveConstraint::Clone() const
234 {
235     return new BoundConjunctiveConstraint(*this);
236 }
237 
238 std::u32string MakeBoundConceptName(ConceptSymbol* conceptSymbolconst std::std::vector<TypeSymbol*>&typeArguments)
239 {
240     std::u32string s = conceptSymbol->GroupName();
241     s.append(1'<');
242     int n = typeArguments.size();
243     for (int i = 0; i < n; ++i)
244     {
245         if (i > 0)
246         {
247             s.append(U", ");
248         }
249         TypeSymbol* typeSymbol = typeArguments[i];
250         s.append(typeSymbol->FullName());
251     }
252     s.append(1'>');
253     return s;
254 }
255 
256 BoundConcept::BoundConcept(ConceptSymbol* conceptSymbol_const std::std::vector<TypeSymbol*>&typeArguments_constSpan&span_constboost::uuids::uuid&moduleId_) :
257     BoundNode(span_moduleId_BoundNodeType::boundConcept)name(MakeBoundConceptName(conceptSymbol_typeArguments_))conceptSymbol(conceptSymbol_)typeArguments(typeArguments_)
258     commonType(nullptr)
259 {
260 }
261 
262 void BoundConcept::Load(Emitter& emitterOperationFlags flags)
263 {
264     throw Exception("cannot load bound concept"GetSpan()ModuleId());
265 }
266 
267 void BoundConcept::Store(Emitter& emitterOperationFlags flags)
268 {
269     throw Exception("cannot store bound concept"GetSpan()ModuleId());
270 }
271 
272 void BoundConcept::Accept(BoundNodeVisitor& visitor)
273 {
274     throw Exception("cannot visit bound concept"GetSpan()ModuleId());
275 }
276 
277 void BoundConcept::SetBoundConstraint(std::std::unique_ptr<BoundConstraint>&&boundConstraint_)
278 {
279     boundConstraint = std::move(boundConstraint_);
280 }
281 
282 void BoundConcept::AddBoundTemplateParameter(std::std::unique_ptr<BoundTemplateParameterSymbol>&&boundTemplateParameter)
283 {
284     boundTemplateParameters.push_back(std::move(boundTemplateParameter));
285 }
286 
287 bool operator==(const BoundConceptKey& leftconst BoundConceptKey& right)
288 {
289     if (left.conceptSymbol != right.conceptSymbol) return false;
290     if (left.Arity() != right.Arity()) return false;
291     int n = left.Arity();
292     for (int i = 0; i < n; ++i)
293     {
294         if (!TypesEqual(left.typeArguments[i]right.typeArguments[i])) return false;
295     }
296     return true;
297 }
298 
299 } } // namespace cmajor::binder