1 #include "yaml-cpp/emitter.h"
2 #include "emitterstate.h"
3 #include "emitterutils.h"
4 #include "indentation.h"
5 #include "yaml-cpp/exceptions.h"
10 Emitter::Emitter(): m_pState(new EmitterState
)
18 const char *Emitter::c_str() const
20 return m_stream
.str();
23 unsigned Emitter::size() const
25 return m_stream
.pos();
29 bool Emitter::good() const
31 return m_pState
->good();
34 const std::string
Emitter::GetLastError() const
36 return m_pState
->GetLastError();
40 bool Emitter::SetOutputCharset(EMITTER_MANIP value
)
42 return m_pState
->SetOutputCharset(value
, GLOBAL
);
45 bool Emitter::SetStringFormat(EMITTER_MANIP value
)
47 return m_pState
->SetStringFormat(value
, GLOBAL
);
50 bool Emitter::SetBoolFormat(EMITTER_MANIP value
)
53 if(m_pState
->SetBoolFormat(value
, GLOBAL
))
55 if(m_pState
->SetBoolCaseFormat(value
, GLOBAL
))
57 if(m_pState
->SetBoolLengthFormat(value
, GLOBAL
))
62 bool Emitter::SetIntBase(EMITTER_MANIP value
)
64 return m_pState
->SetIntFormat(value
, GLOBAL
);
67 bool Emitter::SetSeqFormat(EMITTER_MANIP value
)
69 return m_pState
->SetFlowType(GT_SEQ
, value
, GLOBAL
);
72 bool Emitter::SetMapFormat(EMITTER_MANIP value
)
75 if(m_pState
->SetFlowType(GT_MAP
, value
, GLOBAL
))
77 if(m_pState
->SetMapKeyFormat(value
, GLOBAL
))
82 bool Emitter::SetIndent(unsigned n
)
84 return m_pState
->SetIndent(n
, GLOBAL
);
87 bool Emitter::SetPreCommentIndent(unsigned n
)
89 return m_pState
->SetPreCommentIndent(n
, GLOBAL
);
92 bool Emitter::SetPostCommentIndent(unsigned n
)
94 return m_pState
->SetPostCommentIndent(n
, GLOBAL
);
98 // . Either start/end a group, or set a modifier locally
99 Emitter
& Emitter::SetLocalValue(EMITTER_MANIP value
)
136 m_pState
->SetLocalValue(value
);
142 Emitter
& Emitter::SetLocalIndent(const _Indent
& indent
)
144 m_pState
->SetIndent(indent
.value
, LOCAL
);
148 // GotoNextPreAtomicState
149 // . Runs the state machine, emitting if necessary, and returns 'true' if done (i.e., ready to emit an atom)
150 bool Emitter::GotoNextPreAtomicState()
155 unsigned curIndent
= m_pState
->GetCurIndent();
157 EMITTER_STATE curState
= m_pState
->GetCurState();
160 case ES_WAITING_FOR_DOC
:
161 m_pState
->SwitchState(ES_WRITING_DOC
);
165 case ES_DONE_WITH_DOC
:
170 case ES_WAITING_FOR_BLOCK_SEQ_ENTRY
:
171 m_stream
<< IndentTo(curIndent
) << "-";
172 m_pState
->RequireSoftSeparation();
173 m_pState
->SwitchState(ES_WRITING_BLOCK_SEQ_ENTRY
);
175 case ES_WRITING_BLOCK_SEQ_ENTRY
:
177 case ES_DONE_WITH_BLOCK_SEQ_ENTRY
:
179 m_pState
->SwitchState(ES_WAITING_FOR_BLOCK_SEQ_ENTRY
);
183 case ES_WAITING_FOR_FLOW_SEQ_ENTRY
:
184 m_pState
->SwitchState(ES_WRITING_FLOW_SEQ_ENTRY
);
186 case ES_WRITING_FLOW_SEQ_ENTRY
:
188 case ES_DONE_WITH_FLOW_SEQ_ENTRY
:
190 m_pState
->RequireSoftSeparation();
191 m_pState
->SwitchState(ES_WAITING_FOR_FLOW_SEQ_ENTRY
);
195 case ES_WAITING_FOR_BLOCK_MAP_ENTRY
:
196 m_pState
->SetError(ErrorMsg::EXPECTED_KEY_TOKEN
);
198 case ES_WAITING_FOR_BLOCK_MAP_KEY
:
199 if(m_pState
->CurrentlyInLongKey()) {
200 m_stream
<< IndentTo(curIndent
) << '?';
201 m_pState
->RequireSoftSeparation();
203 m_pState
->SwitchState(ES_WRITING_BLOCK_MAP_KEY
);
205 case ES_WRITING_BLOCK_MAP_KEY
:
207 case ES_DONE_WITH_BLOCK_MAP_KEY
:
208 m_pState
->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN
);
210 case ES_WAITING_FOR_BLOCK_MAP_VALUE
:
211 m_pState
->SwitchState(ES_WRITING_BLOCK_MAP_VALUE
);
213 case ES_WRITING_BLOCK_MAP_VALUE
:
215 case ES_DONE_WITH_BLOCK_MAP_VALUE
:
216 m_pState
->SetError(ErrorMsg::EXPECTED_KEY_TOKEN
);
220 case ES_WAITING_FOR_FLOW_MAP_ENTRY
:
221 m_pState
->SetError(ErrorMsg::EXPECTED_KEY_TOKEN
);
223 case ES_WAITING_FOR_FLOW_MAP_KEY
:
224 m_pState
->SwitchState(ES_WRITING_FLOW_MAP_KEY
);
225 if(m_pState
->CurrentlyInLongKey()) {
226 EmitSeparationIfNecessary();
228 m_pState
->RequireSoftSeparation();
231 case ES_WRITING_FLOW_MAP_KEY
:
233 case ES_DONE_WITH_FLOW_MAP_KEY
:
234 m_pState
->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN
);
236 case ES_WAITING_FOR_FLOW_MAP_VALUE
:
238 m_pState
->RequireSoftSeparation();
239 m_pState
->SwitchState(ES_WRITING_FLOW_MAP_VALUE
);
241 case ES_WRITING_FLOW_MAP_VALUE
:
243 case ES_DONE_WITH_FLOW_MAP_VALUE
:
244 m_pState
->SetError(ErrorMsg::EXPECTED_KEY_TOKEN
);
255 // . Depending on the emitter state, write to the stream to get it
256 // in position to do an atomic write (e.g., scalar, sequence, or map)
257 void Emitter::PreAtomicWrite()
262 while(!GotoNextPreAtomicState())
268 void Emitter::PostAtomicWrite()
273 EMITTER_STATE curState
= m_pState
->GetCurState();
277 m_pState
->SwitchState(ES_DONE_WITH_DOC
);
281 case ES_WRITING_BLOCK_SEQ_ENTRY
:
282 m_pState
->SwitchState(ES_DONE_WITH_BLOCK_SEQ_ENTRY
);
286 case ES_WRITING_FLOW_SEQ_ENTRY
:
287 m_pState
->SwitchState(ES_DONE_WITH_FLOW_SEQ_ENTRY
);
291 case ES_WRITING_BLOCK_MAP_KEY
:
292 if(!m_pState
->CurrentlyInLongKey()) {
294 m_pState
->RequireSoftSeparation();
296 m_pState
->SwitchState(ES_DONE_WITH_BLOCK_MAP_KEY
);
298 case ES_WRITING_BLOCK_MAP_VALUE
:
299 m_pState
->SwitchState(ES_DONE_WITH_BLOCK_MAP_VALUE
);
303 case ES_WRITING_FLOW_MAP_KEY
:
304 m_pState
->SwitchState(ES_DONE_WITH_FLOW_MAP_KEY
);
306 case ES_WRITING_FLOW_MAP_VALUE
:
307 m_pState
->SwitchState(ES_DONE_WITH_FLOW_MAP_VALUE
);
313 m_pState
->ClearModifiedSettings();
316 // EmitSeparationIfNecessary
317 void Emitter::EmitSeparationIfNecessary()
322 if(m_pState
->RequiresSoftSeparation())
324 else if(m_pState
->RequiresHardSeparation())
326 m_pState
->UnsetSeparation();
330 void Emitter::EmitBeginDoc()
335 EMITTER_STATE curState
= m_pState
->GetCurState();
336 if(curState
!= ES_WAITING_FOR_DOC
&& curState
!= ES_WRITING_DOC
&& curState
!= ES_DONE_WITH_DOC
) {
337 m_pState
->SetError("Unexpected begin document");
341 if(curState
== ES_WRITING_DOC
|| curState
== ES_DONE_WITH_DOC
)
345 m_pState
->UnsetSeparation();
346 m_pState
->SwitchState(ES_WAITING_FOR_DOC
);
350 void Emitter::EmitEndDoc()
356 EMITTER_STATE curState
= m_pState
->GetCurState();
357 if(curState
!= ES_WAITING_FOR_DOC
&& curState
!= ES_WRITING_DOC
&& curState
!= ES_DONE_WITH_DOC
) {
358 m_pState
->SetError("Unexpected end document");
362 if(curState
== ES_WRITING_DOC
|| curState
== ES_DONE_WITH_DOC
)
366 m_pState
->UnsetSeparation();
367 m_pState
->SwitchState(ES_WAITING_FOR_DOC
);
371 void Emitter::EmitBeginSeq()
376 // must have a long key if we're emitting a sequence
377 m_pState
->StartLongKey();
381 EMITTER_STATE curState
= m_pState
->GetCurState();
382 EMITTER_MANIP flowType
= m_pState
->GetFlowType(GT_SEQ
);
383 if(flowType
== Block
) {
384 if(curState
== ES_WRITING_BLOCK_SEQ_ENTRY
||
385 curState
== ES_WRITING_BLOCK_MAP_KEY
|| curState
== ES_WRITING_BLOCK_MAP_VALUE
||
386 curState
== ES_WRITING_DOC
388 if(m_pState
->RequiresHardSeparation() || curState
!= ES_WRITING_DOC
) {
390 m_pState
->UnsetSeparation();
393 m_pState
->PushState(ES_WAITING_FOR_BLOCK_SEQ_ENTRY
);
394 } else if(flowType
== Flow
) {
395 EmitSeparationIfNecessary();
397 m_pState
->PushState(ES_WAITING_FOR_FLOW_SEQ_ENTRY
);
401 m_pState
->BeginGroup(GT_SEQ
);
405 void Emitter::EmitEndSeq()
410 if(m_pState
->GetCurGroupType() != GT_SEQ
)
411 return m_pState
->SetError(ErrorMsg::UNEXPECTED_END_SEQ
);
413 EMITTER_STATE curState
= m_pState
->GetCurState();
414 FLOW_TYPE flowType
= m_pState
->GetCurGroupFlowType();
415 if(flowType
== FT_BLOCK
) {
416 // Note: block sequences are *not* allowed to be empty, but we convert it
417 // to a flow sequence if it is
418 assert(curState
== ES_DONE_WITH_BLOCK_SEQ_ENTRY
|| curState
== ES_WAITING_FOR_BLOCK_SEQ_ENTRY
);
419 if(curState
== ES_WAITING_FOR_BLOCK_SEQ_ENTRY
) {
420 // Note: only one of these will actually output anything for a given situation
421 EmitSeparationIfNecessary();
422 unsigned curIndent
= m_pState
->GetCurIndent();
423 m_stream
<< IndentTo(curIndent
);
427 } else if(flowType
== FT_FLOW
) {
428 // Note: flow sequences are allowed to be empty
429 assert(curState
== ES_DONE_WITH_FLOW_SEQ_ENTRY
|| curState
== ES_WAITING_FOR_FLOW_SEQ_ENTRY
);
434 m_pState
->PopState();
435 m_pState
->EndGroup(GT_SEQ
);
441 void Emitter::EmitBeginMap()
446 // must have a long key if we're emitting a map
447 m_pState
->StartLongKey();
451 EMITTER_STATE curState
= m_pState
->GetCurState();
452 EMITTER_MANIP flowType
= m_pState
->GetFlowType(GT_MAP
);
453 if(flowType
== Block
) {
454 if(curState
== ES_WRITING_BLOCK_SEQ_ENTRY
||
455 curState
== ES_WRITING_BLOCK_MAP_KEY
|| curState
== ES_WRITING_BLOCK_MAP_VALUE
||
456 curState
== ES_WRITING_DOC
458 if(m_pState
->RequiresHardSeparation() || (curState
!= ES_WRITING_DOC
&& curState
!= ES_WRITING_BLOCK_SEQ_ENTRY
)) {
460 m_pState
->UnsetSeparation();
463 m_pState
->PushState(ES_WAITING_FOR_BLOCK_MAP_ENTRY
);
464 } else if(flowType
== Flow
) {
465 EmitSeparationIfNecessary();
467 m_pState
->PushState(ES_WAITING_FOR_FLOW_MAP_ENTRY
);
471 m_pState
->BeginGroup(GT_MAP
);
475 void Emitter::EmitEndMap()
480 if(m_pState
->GetCurGroupType() != GT_MAP
)
481 return m_pState
->SetError(ErrorMsg::UNEXPECTED_END_MAP
);
483 EMITTER_STATE curState
= m_pState
->GetCurState();
484 FLOW_TYPE flowType
= m_pState
->GetCurGroupFlowType();
485 if(flowType
== FT_BLOCK
) {
486 // Note: block sequences are *not* allowed to be empty, but we convert it
487 // to a flow sequence if it is
488 assert(curState
== ES_DONE_WITH_BLOCK_MAP_VALUE
|| curState
== ES_WAITING_FOR_BLOCK_MAP_ENTRY
);
489 if(curState
== ES_WAITING_FOR_BLOCK_MAP_ENTRY
) {
490 // Note: only one of these will actually output anything for a given situation
491 EmitSeparationIfNecessary();
492 unsigned curIndent
= m_pState
->GetCurIndent();
493 m_stream
<< IndentTo(curIndent
);
496 } else if(flowType
== FT_FLOW
) {
497 // Note: flow maps are allowed to be empty
498 assert(curState
== ES_DONE_WITH_FLOW_MAP_VALUE
|| curState
== ES_WAITING_FOR_FLOW_MAP_ENTRY
);
503 m_pState
->PopState();
504 m_pState
->EndGroup(GT_MAP
);
510 void Emitter::EmitKey()
515 EMITTER_STATE curState
= m_pState
->GetCurState();
516 FLOW_TYPE flowType
= m_pState
->GetCurGroupFlowType();
517 if(curState
!= ES_WAITING_FOR_BLOCK_MAP_ENTRY
&& curState
!= ES_DONE_WITH_BLOCK_MAP_VALUE
518 && curState
!= ES_WAITING_FOR_FLOW_MAP_ENTRY
&& curState
!= ES_DONE_WITH_FLOW_MAP_VALUE
)
519 return m_pState
->SetError(ErrorMsg::UNEXPECTED_KEY_TOKEN
);
521 if(flowType
== FT_BLOCK
) {
522 if(curState
== ES_DONE_WITH_BLOCK_MAP_VALUE
)
524 unsigned curIndent
= m_pState
->GetCurIndent();
525 m_stream
<< IndentTo(curIndent
);
526 m_pState
->UnsetSeparation();
527 m_pState
->SwitchState(ES_WAITING_FOR_BLOCK_MAP_KEY
);
528 } else if(flowType
== FT_FLOW
) {
529 if(curState
== ES_DONE_WITH_FLOW_MAP_VALUE
) {
531 m_pState
->RequireSoftSeparation();
533 m_pState
->SwitchState(ES_WAITING_FOR_FLOW_MAP_KEY
);
537 if(m_pState
->GetMapKeyFormat() == LongKey
)
538 m_pState
->StartLongKey();
539 else if(m_pState
->GetMapKeyFormat() == Auto
)
540 m_pState
->StartSimpleKey();
546 void Emitter::EmitValue()
551 EMITTER_STATE curState
= m_pState
->GetCurState();
552 FLOW_TYPE flowType
= m_pState
->GetCurGroupFlowType();
553 if(curState
!= ES_DONE_WITH_BLOCK_MAP_KEY
&& curState
!= ES_DONE_WITH_FLOW_MAP_KEY
)
554 return m_pState
->SetError(ErrorMsg::UNEXPECTED_VALUE_TOKEN
);
556 if(flowType
== FT_BLOCK
) {
557 if(m_pState
->CurrentlyInLongKey()) {
559 m_stream
<< IndentTo(m_pState
->GetCurIndent());
561 m_pState
->RequireSoftSeparation();
563 m_pState
->SwitchState(ES_WAITING_FOR_BLOCK_MAP_VALUE
);
564 } else if(flowType
== FT_FLOW
) {
565 m_pState
->SwitchState(ES_WAITING_FOR_FLOW_MAP_VALUE
);
571 void Emitter::EmitNewline()
576 if(CanEmitNewline()) {
578 m_pState
->UnsetSeparation();
582 bool Emitter::CanEmitNewline() const
584 FLOW_TYPE flowType
= m_pState
->GetCurGroupFlowType();
585 if(flowType
== FT_BLOCK
&& m_pState
->CurrentlyInLongKey())
588 EMITTER_STATE curState
= m_pState
->GetCurState();
589 return curState
!= ES_DONE_WITH_BLOCK_MAP_KEY
&& curState
!= ES_WAITING_FOR_BLOCK_MAP_VALUE
&& curState
!= ES_WRITING_BLOCK_MAP_VALUE
;
592 // *******************************************************************************************
593 // overloads of Write
595 Emitter
& Emitter::Write(const std::string
& str
)
600 // literal scalars must use long keys
601 if(m_pState
->GetStringFormat() == Literal
&& m_pState
->GetCurGroupFlowType() != FT_FLOW
)
602 m_pState
->StartLongKey();
605 EmitSeparationIfNecessary();
607 bool escapeNonAscii
= m_pState
->GetOutputCharset() == EscapeNonAscii
;
608 EMITTER_MANIP strFmt
= m_pState
->GetStringFormat();
609 FLOW_TYPE flowType
= m_pState
->GetCurGroupFlowType();
610 unsigned curIndent
= m_pState
->GetCurIndent();
614 Utils::WriteString(m_stream
, str
, flowType
== FT_FLOW
, escapeNonAscii
);
617 if(!Utils::WriteSingleQuotedString(m_stream
, str
)) {
618 m_pState
->SetError(ErrorMsg::SINGLE_QUOTED_CHAR
);
623 Utils::WriteDoubleQuotedString(m_stream
, str
, escapeNonAscii
);
626 if(flowType
== FT_FLOW
)
627 Utils::WriteString(m_stream
, str
, flowType
== FT_FLOW
, escapeNonAscii
);
629 Utils::WriteLiteralString(m_stream
, str
, curIndent
+ m_pState
->GetIndent());
639 void Emitter::PreWriteIntegralType(std::stringstream
& str
)
642 EmitSeparationIfNecessary();
644 EMITTER_MANIP intFmt
= m_pState
->GetIntFormat();
660 void Emitter::PreWriteStreamable(std::stringstream
& str
)
663 EmitSeparationIfNecessary();
667 void Emitter::PostWriteIntegralType(const std::stringstream
& str
)
669 m_stream
<< str
.str();
673 void Emitter::PostWriteStreamable(const std::stringstream
& str
)
675 m_stream
<< str
.str();
679 const char *Emitter::ComputeFullBoolName(bool b
) const
681 const EMITTER_MANIP mainFmt
= (m_pState
->GetBoolLengthFormat() == ShortBool
? YesNoBool
: m_pState
->GetBoolFormat());
682 const EMITTER_MANIP caseFmt
= m_pState
->GetBoolCaseFormat();
686 case UpperCase
: return b
? "YES" : "NO";
687 case CamelCase
: return b
? "Yes" : "No";
688 case LowerCase
: return b
? "yes" : "no";
694 case UpperCase
: return b
? "ON" : "OFF";
695 case CamelCase
: return b
? "On" : "Off";
696 case LowerCase
: return b
? "on" : "off";
702 case UpperCase
: return b
? "TRUE" : "FALSE";
703 case CamelCase
: return b
? "True" : "False";
704 case LowerCase
: return b
? "true" : "false";
711 return b
? "y" : "n"; // should never get here, but it can't hurt to give these answers
714 Emitter
& Emitter::Write(bool b
)
720 EmitSeparationIfNecessary();
722 const char *name
= ComputeFullBoolName(b
);
723 if(m_pState
->GetBoolLengthFormat() == ShortBool
)
732 Emitter
& Emitter::Write(const _Alias
& alias
)
738 EmitSeparationIfNecessary();
739 if(!Utils::WriteAlias(m_stream
, alias
.content
)) {
740 m_pState
->SetError(ErrorMsg::INVALID_ALIAS
);
747 Emitter
& Emitter::Write(const _Anchor
& anchor
)
753 EmitSeparationIfNecessary();
754 if(!Utils::WriteAnchor(m_stream
, anchor
.content
)) {
755 m_pState
->SetError(ErrorMsg::INVALID_ANCHOR
);
758 m_pState
->RequireHardSeparation();
759 // Note: no PostAtomicWrite() because we need another value for this node
763 Emitter
& Emitter::Write(const _Tag
& tag
)
769 EmitSeparationIfNecessary();
771 bool success
= false;
772 if(tag
.type
== _Tag::Type::Verbatim
)
773 success
= Utils::WriteTag(m_stream
, tag
.content
, true);
774 else if(tag
.type
== _Tag::Type::PrimaryHandle
)
775 success
= Utils::WriteTag(m_stream
, tag
.content
, false);
777 success
= Utils::WriteTagWithPrefix(m_stream
, tag
.prefix
, tag
.content
);
780 m_pState
->SetError(ErrorMsg::INVALID_TAG
);
784 m_pState
->RequireHardSeparation();
785 // Note: no PostAtomicWrite() because we need another value for this node
789 void Emitter::EmitKindTag()
794 Emitter
& Emitter::Write(const _Comment
& comment
)
799 m_stream
<< Indentation(m_pState
->GetPreCommentIndent());
800 Utils::WriteComment(m_stream
, comment
.content
, m_pState
->GetPostCommentIndent());
804 Emitter
& Emitter::Write(const _Null
& /*null*/)
810 EmitSeparationIfNecessary();
816 Emitter
& Emitter::Write(const _Binary
& binary
)
818 Write(SecondaryTag("binary"));
824 EmitSeparationIfNecessary();
825 Utils::WriteBinary(m_stream
, binary
.data
, binary
.size
);