Om
operator.cpp
Go to the documentation of this file.
1 
15 #ifndef Om_Language_Operator_
16 
17  #include "om/language/operator.hpp"
18 
19  #ifdef Om_Macro_Test_
20 
21  #include "om/language/system.hpp"
22 
23  #ifndef Om_Macro_Precompilation_
24 
25  #include "boost/test/unit_test.hpp"
26 
27  #endif
28 
29 namespace Om {
30 
31  namespace Language {
32 
33  BOOST_AUTO_TEST_SUITE(OperatorTest)
34 
35  BOOST_AUTO_TEST_CASE(BasicTest) {
36  BOOST_CHECK_EQUAL(
37  "{a` `{b`}}",
38  System::Get().Evaluate("operator{a {b}}")
39  );
40  }
41 
42  BOOST_AUTO_TEST_CASE(DereferenceTest) {
43  {
44  Operator theMutableOperator;
45  Atom & theMutableAtom = theMutableOperator;
46  Program & theMutableDereference = *theMutableAtom;
47  BOOST_CHECK(
48  typeid(theMutableDereference) == typeid(Null)
49  );
50  }
51 
52  {
53  Operator const theImmutableOperator;
54  Atom const & theImmutableAtom = theImmutableOperator;
55  Program const & theImmutableDereference = *theImmutableAtom;
56  BOOST_CHECK(
57  typeid(theImmutableDereference) == typeid(Null)
58  );
59  }
60  }
61 
62  BOOST_AUTO_TEST_CASE(EqualityTest) {
63  // Positive match
64  BOOST_CHECK_EQUAL(
65  "{{test` `{ing`}}}",
66  System::Get().Evaluate("= operator{test {ing}} {test` `{ing`}}")
67  );
68 
69  // Positive match
70  BOOST_CHECK_EQUAL(
71  "{{a`{b`}`{c`}`\nd`{e`}}}",
72  System::Get().Evaluate("= operator{a{b}{c}\nd{e}} {a`{b`}`{c`}`\nd`{e`}}")
73  );
74 
75  // Negative match
76  BOOST_CHECK_EQUAL(
77  "{}",
78  System::Get().Evaluate("= operator{a{b}{c}} {a`{b`}`{d`}}")
79  );
80 
81  // Empty match
82  BOOST_CHECK_EQUAL(
83  "{}",
84  System::Get().Evaluate("= operator{} {a{b}{c}}")
85  );
86 
87  // Empty match
88  BOOST_CHECK_EQUAL(
89  "{{}}",
90  System::Get().Evaluate("= operator{} {}")
91  );
92  }
93 
94  BOOST_AUTO_TEST_CASE(TakeQuotedElementsTest) {
95  Operator theOperator;
96  {
97  Literal theLiteral;
98  {
99  Om::Source::CodePointSource<> theCodePointSource("a{b{c}}");
100  Reader theReader(theCodePointSource);
101  theLiteral.ParseElements(theReader);
102  }
103  theOperator.TakeQuotedProducer(theLiteral);
104  assert(
105  theLiteral.IsEmpty()
106  );
107  }
108  BOOST_CHECK_EQUAL(
109  "{a{b{c}}}",
110  theOperator.GetString()
111  );
112  }
113 
114  BOOST_AUTO_TEST_CASE(NormalizationTest) {
115  // Test combining character reordering under NFD.
116  Operator theFirst("s\xCC\x87");
117  Operator theSecond("\xCC\xA3");
118  theFirst.TakeElement(theSecond);
119  BOOST_CHECK_EQUAL(
120  "s\xCC\xA3\xCC\x87",
121  theFirst.GetString()
122  );
123  }
124 
125  BOOST_AUTO_TEST_CASE(ReadTest) {
126  char const theCode[] = "0\n\t {1\n\t {2\n\t } 3\n\t } {4\n\t} 5\n";
127  std::string theResult;
128  {
130  std::back_insert_iterator<std::string>
131  > theCodePointSink(
132  std::back_inserter(theResult)
133  );
134  Writer theWriter(theCodePointSink);
135 
136  Om::Source::CodePointSource<> theCodePointSource(theCode);
137  Reader theReader(theCodePointSource);
138  Operator theOperator;
139  theOperator.ParseElements(theReader);
140  theOperator.GiveElements(theWriter);
141  }
142  BOOST_CHECK_EQUAL(
143  (
144  "0`\n"
145  "`\t` `{1`\n"
146  "`\t` `{2`\n"
147  "`\t` `}` 3`\n"
148  "`\t` `}` `{4`\n"
149  "`\t`}` 5`\n"
150  ),
151  theResult
152  );
153  }
154 
155  BOOST_AUTO_TEST_SUITE_END()
156 
157  }
158 
159 }
160 
161  #endif
162 
163 #else
164 
165  #include "om/language/operand.hpp"
166  #include "om/language/separator.hpp"
167  #include "om/language/writer.hpp"
168  #include "om/sink/code_point_sink.hpp"
172 
173 // MARK: - Om::Language::Operator
174 
175  #define Type_ \
176  Om::Language::Operator
177 
178 // MARK: public (static)
179 
180 inline char const * Type_::GetName() {
182 }
183 
184 // MARK: public (non-static)
185 
186 inline Type_::Operator() {}
187 
188 inline Type_::Operator(std::string const & theString) {
189  boost::locale::normalize(
190  theString,
191  boost::locale::norm_nfd
192  ).swap(this->thisString);
193 }
194 
195 inline Type_::Operator(
196  char const theCodeUnitIterator[]
197 ) {
198  boost::locale::normalize(
199  theCodeUnitIterator,
200  boost::locale::norm_nfd
201  ).swap(this->thisString);
202 }
203 
204 inline Type_::Operator(
205  Om::Source::Source<CodePoint const> & theCodePointSource
206 ) {
207  std::string theString;
208  for (
209  std::back_insert_iterator<std::string> theInserter(theString);
210  theCodePointSource;
211  theCodePointSource.Pop()
212  ) {
213  switch (*theCodePointSource) {
215  // Fall through.
217  break;
219  theCodePointSource.Pop();
220  if (!theCodePointSource) {
221  theString.push_back(Symbol::theEndOperandSymbol);
222  break;
223  }
224  // Fall through.
225  default:
226  Utf8::encode(
227  *theCodePointSource,
228  theInserter
229  );
230  continue;
231  }
232  break;
233  }
234  boost::locale::normalize(
235  theString,
236  boost::locale::norm_nfd
237  ).swap(this->thisString);
238 }
239 
240 inline Type_::Operator(Symbol::OperandSymbol const theOperandSymbol):
241 DefaultAtom<Operator>(
242  static_cast<char>(theOperandSymbol)
243 ) {}
244 
245 inline Type_::Operator(Symbol::OperatorSymbol const theOperatorSymbol):
246 DefaultAtom<Operator>(
247  static_cast<char>(theOperatorSymbol)
248 ) {}
249 
250 inline Type_::Operator(Symbol::SeparatorSymbol const theSeparatorSymbol):
251 DefaultAtom<Operator>(
252  static_cast<char>(theSeparatorSymbol)
253 ) {}
254 
255 inline Type_ & Type_::operator =(Operator theOperator) {
256  this->Swap(theOperator);
257  return *this;
258 }
259 
260 inline void Type_::BackGiveCodePoint(Consumer & theConsumer) {
261  if (
262  !this->thisString.empty()
263  ) {
264  Operator theOperator;
265  {
266  std::string & theString = theOperator.thisString;
267  {
269  this->thisString.begin(),
270  this->thisString.end()
271  );
272  assert(theCodePointStringRange);
273  theCodePointStringRange->swap(theString);
274  }
275  assert(
276  !theString.empty()
277  );
278  this->thisString.erase(
279  this->thisString.size() - theString.size()
280  );
281  }
282  theConsumer.TakeElement(theOperator);
283  }
284 }
285 
286 template <boost::locale::boundary::boundary_type theSegment>
287 inline void Type_::BackGiveSegment(Consumer & theConsumer) {
288  if (
289  !this->thisString.empty()
290  ) {
291  Operator theOperator;
292  {
293  std::string & theString = theOperator.thisString;
294  {
295  typedef boost::locale::boundary::segment_index<std::string::const_iterator> SegmentCollection;
296 
297  typedef SegmentCollection::const_iterator SegmentIterator;
298 
299  SegmentCollection const theSegmentCollection(
300  static_cast<boost::locale::boundary::boundary_type>(theSegment),
301  this->thisString.begin(),
302  this->thisString.end()
303  );
304 
305  SegmentIterator theSegmentIterator(
306  theSegmentCollection.end()
307  );
308  assert(
309  theSegmentCollection.begin() != theSegmentIterator
310  );
311  --theSegmentIterator;
312  theSegmentIterator->str().swap(theString);
313  }
314  assert(
315  !theString.empty()
316  );
317  this->thisString.erase(
318  this->thisString.size() - theString.size()
319  );
320  }
321  theConsumer.TakeElement(theOperator);
322  }
323 }
324 
325 template <typename TheConsumer>
326 inline void Type_::Decode(TheConsumer & theConsumer) const {
328  this->thisString.begin(),
329  this->thisString.end()
330  );
331  Reader theReader(theCodePointSource);
332  theConsumer.ParseElements(theReader);
333 }
334 
335 template <typename TheProducer>
336 inline void Type_::Encode(TheProducer & theProducer) {
337  this->thisString.clear();
339  std::back_insert_iterator<std::string>
340  > theCodePointSink(
341  std::back_inserter(this->thisString)
342  );
343  Writer theWriter(theCodePointSink);
344  theProducer.GiveElements(theWriter);
345 }
346 
347 inline void Type_::FrontGiveCodePoint(Consumer & theConsumer) {
348  if (
349  !this->thisString.empty()
350  ) {
351  Operator theOperator;
352  {
353  std::string & theString = theOperator.thisString;
354  {
356  this->thisString.begin(),
357  this->thisString.end()
358  );
359  assert(theCodePointStringRange);
360  theCodePointStringRange->swap(theString);
361  }
362  assert(
363  !theString.empty()
364  );
365  this->thisString.erase(
366  0,
367  theString.size()
368  );
369  }
370  theConsumer.TakeElement(theOperator);
371  }
372 }
373 
374 template <boost::locale::boundary::boundary_type theSegment>
375 inline void Type_::FrontGiveSegment(Consumer & theConsumer) {
376  if (
377  !this->thisString.empty()
378  ) {
379  Operator theOperator;
380  {
381  std::string & theString = theOperator.thisString;
382  {
383  typedef boost::locale::boundary::segment_index<std::string::const_iterator> SegmentCollection;
384 
385  SegmentCollection const theSegmentCollection(
386  static_cast<boost::locale::boundary::boundary_type>(theSegment),
387  this->thisString.begin(),
388  this->thisString.end()
389  );
390 
391  SegmentCollection::const_iterator const theSegmentIterator(
392  theSegmentCollection.begin()
393  );
394  assert(
395  theSegmentCollection.end() != theSegmentIterator
396  );
397  theSegmentIterator->str().swap(theString);
398  }
399  assert(
400  !theString.empty()
401  );
402  this->thisString.erase(
403  0,
404  theString.size()
405  );
406  }
407  theConsumer.TakeElement(theOperator);
408  }
409 }
410 
411 inline void Type_::Normalize() {
412  boost::locale::normalize(
413  this->thisString,
414  boost::locale::norm_nfkd
415  ).swap(this->thisString);
416 }
417 
418 inline void Type_::ParseElements(Reader & theReader) {
419  while (theReader) {
420  switch (*theReader) {
422  // Fall through.
424  // Fall through.
426  this->thisString.push_back(
427  static_cast<char>(*theReader)
428  );
429  theReader.Pop();
430  continue;
431  }
432  Operator theOperator(theReader);
433  this->TakeOperator(theOperator);
434  }
435 }
436 
437 inline void Type_::ParseQuotedElements(Reader & theReader) {
438  this->thisString.push_back(Symbol::theStartOperandSymbol);
439  this->ParseElements(theReader);
440  this->thisString.push_back(Symbol::theEndOperandSymbol);
441 }
442 
443 template <typename TheOperand>
444 inline void Type_::TakeOperand(TheOperand & theOperand) {
445  assert(
446  !theOperand.IsEmpty()
447  );
448  this->TakeQuotedProducer(
449  *theOperand.GetProgram()
450  );
451 }
452 
453 template <typename TheOperator>
454 inline void Type_::TakeOperator(TheOperator & theOperator) {
455  assert(
456  typeid(theOperator) == typeid(*this)
457  );
458  assert(
459  !theOperator.IsEmpty()
460  );
461  assert(
462  boost::locale::normalize(
463  theOperator.thisString,
464  boost::locale::norm_nfd
465  ) == theOperator.thisString &&
466  "Operator strings must be NFC normalized."
467  );
468 
469  if (
470  this->IsEmpty()
471  ) {
472  this->Take(theOperator);
473  return;
474  }
475 
476  this->thisString.append(theOperator.thisString);
477 
478  // Normalization is required even when combining two NFD-normalized strings.
479  // TODO: Optimize to only do an incremental normalization at the boundary.
480  boost::locale::normalize(
481  this->thisString,
482  boost::locale::norm_nfd
483  ).swap(this->thisString);
484 }
485 
486 template <typename TheProducer>
487 inline void Type_::TakeQuotedProducer(TheProducer & theProducer) {
488  this->thisString.push_back(Symbol::theStartOperandSymbol);
489  theProducer.GiveElements(*this);
490  this->thisString.push_back(Symbol::theEndOperandSymbol);
491 }
492 
493 template <typename TheSeparator>
494 inline void Type_::TakeSeparator(TheSeparator & theSeparator) {
495  assert(
496  !theSeparator.IsEmpty()
497  );
498  this->thisString.append(
499  theSeparator.GetString()
500  );
501 }
502 
503  #undef Type_
504 
505 // MARK: - boost::
506 
507 template <>
508 inline void boost::swap(
509  Om::Language::Operator & theFirst,
510  Om::Language::Operator & theSecond
511 ) {
512  theFirst.Swap(theSecond);
513 }
514 
515 #endif
void Swap(ThisImplementation &)
The Operator implementation.
Definition: operator.hpp:60
static System & Get()
A CodePoint Sink that pushes each code unit to the iterator.
A CodePoint Source that reads each code unit from the iterator.
A Source of CodePoint strings from the back of a string.
A Source of CodePoint strings from the front of a string.
Any object that items can be pulled from.
Definition: source.hpp:31
virtual void Pop()=0
Pops the current item.
Om header file.
Om header file.
SeparatorSymbol
A Separator symbol.
OperatorSymbol
An Operator symbol.
OperandSymbol
An Operand symbol.
The Om library.
Definition: code_point.hpp:26
void swap(Om::Language::Expression &, Om::Language::Expression &)
Om header file.
#define Om_Language_Symbol_OperandSymbol_GetCases_()
Generates switch cases for each Om::Language::Symbol::OperandSymbol.
Om header file.
#define Om_Language_Operator_GetName_()
Definition: operator.hpp:42
Om header file.
#define Om_Language_Symbol_SeparatorSymbol_GetCases_()
Generates switch cases for each Om::Language::Symbol::SeparatorSymbol.
Om header file.
Om header file.