summaryrefslogtreecommitdiffstats
path: root/yaml-cpp/src/emitter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'yaml-cpp/src/emitter.cpp')
-rwxr-xr-xyaml-cpp/src/emitter.cpp882
1 files changed, 882 insertions, 0 deletions
diff --git a/yaml-cpp/src/emitter.cpp b/yaml-cpp/src/emitter.cpp
new file mode 100755
index 00000000..91f48da7
--- /dev/null
+++ b/yaml-cpp/src/emitter.cpp
@@ -0,0 +1,882 @@
+#include "yaml-cpp/emitter.h"
+#include "emitterstate.h"
+#include "emitterutils.h"
+#include "indentation.h"
+#include "yaml-cpp/exceptions.h"
+#include <sstream>
+
+namespace YAML
+{
+ Emitter::Emitter(): m_pState(new EmitterState)
+ {
+ }
+
+ Emitter::~Emitter()
+ {
+ }
+
+ const char *Emitter::c_str() const
+ {
+ return m_stream.str();
+ }
+
+ unsigned Emitter::size() const
+ {
+ return m_stream.pos();
+ }
+
+ // state checking
+ bool Emitter::good() const
+ {
+ return m_pState->good();
+ }
+
+ const std::string Emitter::GetLastError() const
+ {
+ return m_pState->GetLastError();
+ }
+
+ // global setters
+ bool Emitter::SetOutputCharset(EMITTER_MANIP value)
+ {
+ return m_pState->SetOutputCharset(value, GLOBAL);
+ }
+
+ bool Emitter::SetStringFormat(EMITTER_MANIP value)
+ {
+ return m_pState->SetStringFormat(value, GLOBAL);
+ }
+
+ bool Emitter::SetBoolFormat(EMITTER_MANIP value)
+ {
+ bool ok = false;
+ if(m_pState->SetBoolFormat(value, GLOBAL))
+ ok = true;
+ if(m_pState->SetBoolCaseFormat(value, GLOBAL))
+ ok = true;
+ if(m_pState->SetBoolLengthFormat(value, GLOBAL))
+ ok = true;
+ return ok;
+ }
+
+ bool Emitter::SetIntBase(EMITTER_MANIP value)
+ {
+ return m_pState->SetIntFormat(value, GLOBAL);
+ }
+
+ bool Emitter::SetSeqFormat(EMITTER_MANIP value)
+ {
+ return m_pState->SetFlowType(GT_SEQ, value, GLOBAL);
+ }
+
+ bool Emitter::SetMapFormat(EMITTER_MANIP value)
+ {
+ bool ok = false;
+ if(m_pState->SetFlowType(GT_MAP, value, GLOBAL))
+ ok = true;
+ if(m_pState->SetMapKeyFormat(value, GLOBAL))
+ ok = true;
+ return ok;
+ }
+
+ bool Emitter::SetIndent(unsigned n)
+ {
+ return m_pState->SetIndent(n, GLOBAL);
+ }
+
+ bool Emitter::SetPreCommentIndent(unsigned n)
+ {
+ return m_pState->SetPreCommentIndent(n, GLOBAL);
+ }
+
+ bool Emitter::SetPostCommentIndent(unsigned n)
+ {
+ return m_pState->SetPostCommentIndent(n, GLOBAL);
+ }
+
+ bool Emitter::SetFloatPrecision(unsigned n)
+ {
+ return m_pState->SetFloatPrecision(n, GLOBAL);
+ }
+
+ bool Emitter::SetDoublePrecision(unsigned n)
+ {
+ return m_pState->SetDoublePrecision(n, GLOBAL);
+ }
+
+ // SetLocalValue
+ // . Either start/end a group, or set a modifier locally
+ Emitter& Emitter::SetLocalValue(EMITTER_MANIP value)
+ {
+ if(!good())
+ return *this;
+
+ switch(value) {
+ case BeginDoc:
+ EmitBeginDoc();
+ break;
+ case EndDoc:
+ EmitEndDoc();
+ break;
+ case BeginSeq:
+ EmitBeginSeq();
+ break;
+ case EndSeq:
+ EmitEndSeq();
+ break;
+ case BeginMap:
+ EmitBeginMap();
+ break;
+ case EndMap:
+ EmitEndMap();
+ break;
+ case Key:
+ EmitKey();
+ break;
+ case Value:
+ EmitValue();
+ break;
+ case TagByKind:
+ EmitKindTag();
+ break;
+ case Newline:
+ EmitNewline();
+ break;
+ default:
+ m_pState->SetLocalValue(value);
+ break;
+ }
+ return *this;
+ }
+
+ Emitter& Emitter::SetLocalIndent(const _Indent& indent)
+ {
+ m_pState->SetIndent(indent.value, LOCAL);
+ return *this;
+ }
+
+ Emitter& Emitter::SetLocalPrecision(const _Precision& precision)
+ {
+ if(precision.floatPrecision >= 0)
+ m_pState->SetFloatPrecision(precision.floatPrecision, LOCAL);
+ if(precision.doublePrecision >= 0)
+ m_pState->SetDoublePrecision(precision.doublePrecision, LOCAL);
+ return *this;
+ }
+
+ // GotoNextPreAtomicState
+ // . Runs the state machine, emitting if necessary, and returns 'true' if done (i.e., ready to emit an atom)
+ bool Emitter::GotoNextPreAtomicState()
+ {
+ if(!good())
+ return true;
+
+ unsigned curIndent = m_pState->GetCurIndent();
+
+ EMITTER_STATE curState = m_pState->GetCurState();
+ switch(curState) {
+ // document-level
+ case ES_WAITING_FOR_DOC:
+ m_pState->SwitchState(ES_WRITING_DOC);
+ return true;
+ case ES_WRITING_DOC:
+ return true;
+ case ES_DONE_WITH_DOC:
+ EmitBeginDoc();
+ return false;
+
+ // block sequence
+ case ES_WAITING_FOR_BLOCK_SEQ_ENTRY:
+ m_stream << IndentTo(curIndent) << "-";
+ m_pState->RequireSoftSeparation();
+ m_pState->SwitchState(ES_WRITING_BLOCK_SEQ_ENTRY);
+ return true;
+ case ES_WRITING_BLOCK_SEQ_ENTRY:
+ return true;
+ case ES_DONE_WITH_BLOCK_SEQ_ENTRY:
+ m_stream << '\n';
+ m_pState->SwitchState(ES_WAITING_FOR_BLOCK_SEQ_ENTRY);
+ return false;
+
+ // flow sequence
+ case ES_WAITING_FOR_FLOW_SEQ_ENTRY:
+ m_pState->SwitchState(ES_WRITING_FLOW_SEQ_ENTRY);
+ return true;
+ case ES_WRITING_FLOW_SEQ_ENTRY:
+ return true;
+ case ES_DONE_WITH_FLOW_SEQ_ENTRY:
+ EmitSeparationIfNecessary();
+ m_stream << ',';
+ m_pState->RequireSoftSeparation();
+ m_pState->SwitchState(ES_WAITING_FOR_FLOW_SEQ_ENTRY);
+ return false;
+
+ // block map
+ case ES_WAITING_FOR_BLOCK_MAP_ENTRY:
+ m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN);
+ return true;
+ case ES_WAITING_FOR_BLOCK_MAP_KEY:
+ if(m_pState->CurrentlyInLongKey()) {
+ m_stream << IndentTo(curIndent) << '?';
+ m_pState->RequireSoftSeparation();
+ }
+ m_pState->SwitchState(ES_WRITING_BLOCK_MAP_KEY);
+ return true;
+ case ES_WRITING_BLOCK_MAP_KEY:
+ return true;
+ case ES_DONE_WITH_BLOCK_MAP_KEY:
+ m_pState->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN);
+ return true;
+ case ES_WAITING_FOR_BLOCK_MAP_VALUE:
+ m_pState->SwitchState(ES_WRITING_BLOCK_MAP_VALUE);
+ return true;
+ case ES_WRITING_BLOCK_MAP_VALUE:
+ return true;
+ case ES_DONE_WITH_BLOCK_MAP_VALUE:
+ m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN);
+ return true;
+
+ // flow map
+ case ES_WAITING_FOR_FLOW_MAP_ENTRY:
+ m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN);
+ return true;
+ case ES_WAITING_FOR_FLOW_MAP_KEY:
+ EmitSeparationIfNecessary();
+ m_pState->SwitchState(ES_WRITING_FLOW_MAP_KEY);
+ if(m_pState->CurrentlyInLongKey()) {
+ m_stream << '?';
+ m_pState->RequireSoftSeparation();
+ }
+ return true;
+ case ES_WRITING_FLOW_MAP_KEY:
+ return true;
+ case ES_DONE_WITH_FLOW_MAP_KEY:
+ m_pState->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN);
+ return true;
+ case ES_WAITING_FOR_FLOW_MAP_VALUE:
+ EmitSeparationIfNecessary();
+ m_stream << ':';
+ m_pState->RequireSoftSeparation();
+ m_pState->SwitchState(ES_WRITING_FLOW_MAP_VALUE);
+ return true;
+ case ES_WRITING_FLOW_MAP_VALUE:
+ return true;
+ case ES_DONE_WITH_FLOW_MAP_VALUE:
+ m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN);
+ return true;
+ default:
+ assert(false);
+ }
+
+ assert(false);
+ return true;
+ }
+
+ // PreAtomicWrite
+ // . Depending on the emitter state, write to the stream to get it
+ // in position to do an atomic write (e.g., scalar, sequence, or map)
+ void Emitter::PreAtomicWrite()
+ {
+ if(!good())
+ return;
+
+ while(!GotoNextPreAtomicState())
+ ;
+ }
+
+ // PostAtomicWrite
+ // . Clean up
+ void Emitter::PostAtomicWrite()
+ {
+ if(!good())
+ return;
+
+ EMITTER_STATE curState = m_pState->GetCurState();
+ switch(curState) {
+ // document-level
+ case ES_WRITING_DOC:
+ m_pState->SwitchState(ES_DONE_WITH_DOC);
+ break;
+
+ // block seq
+ case ES_WRITING_BLOCK_SEQ_ENTRY:
+ m_pState->SwitchState(ES_DONE_WITH_BLOCK_SEQ_ENTRY);
+ break;
+
+ // flow seq
+ case ES_WRITING_FLOW_SEQ_ENTRY:
+ m_pState->SwitchState(ES_DONE_WITH_FLOW_SEQ_ENTRY);
+ break;
+
+ // block map
+ case ES_WRITING_BLOCK_MAP_KEY:
+ if(!m_pState->CurrentlyInLongKey()) {
+ m_stream << ':';
+ m_pState->RequireSoftSeparation();
+ }
+ m_pState->SwitchState(ES_DONE_WITH_BLOCK_MAP_KEY);
+ break;
+ case ES_WRITING_BLOCK_MAP_VALUE:
+ m_pState->SwitchState(ES_DONE_WITH_BLOCK_MAP_VALUE);
+ break;
+
+ // flow map
+ case ES_WRITING_FLOW_MAP_KEY:
+ m_pState->SwitchState(ES_DONE_WITH_FLOW_MAP_KEY);
+ break;
+ case ES_WRITING_FLOW_MAP_VALUE:
+ m_pState->SwitchState(ES_DONE_WITH_FLOW_MAP_VALUE);
+ break;
+ default:
+ assert(false);
+ };
+
+ m_pState->ClearModifiedSettings();
+ }
+
+ // EmitSeparationIfNecessary
+ void Emitter::EmitSeparationIfNecessary()
+ {
+ if(!good())
+ return;
+
+ if(m_pState->RequiresSoftSeparation())
+ m_stream << ' ';
+ else if(m_pState->RequiresHardSeparation())
+ m_stream << '\n';
+ m_pState->UnsetSeparation();
+ }
+
+ // EmitBeginDoc
+ void Emitter::EmitBeginDoc()
+ {
+ if(!good())
+ return;
+
+ EMITTER_STATE curState = m_pState->GetCurState();
+ if(curState != ES_WAITING_FOR_DOC && curState != ES_WRITING_DOC && curState != ES_DONE_WITH_DOC) {
+ m_pState->SetError("Unexpected begin document");
+ return;
+ }
+
+ if(curState == ES_WRITING_DOC || curState == ES_DONE_WITH_DOC)
+ m_stream << '\n';
+ m_stream << "---\n";
+
+ m_pState->UnsetSeparation();
+ m_pState->SwitchState(ES_WAITING_FOR_DOC);
+ }
+
+ // EmitEndDoc
+ void Emitter::EmitEndDoc()
+ {
+ if(!good())
+ return;
+
+
+ EMITTER_STATE curState = m_pState->GetCurState();
+ if(curState != ES_WAITING_FOR_DOC && curState != ES_WRITING_DOC && curState != ES_DONE_WITH_DOC) {
+ m_pState->SetError("Unexpected end document");
+ return;
+ }
+
+ if(curState == ES_WRITING_DOC || curState == ES_DONE_WITH_DOC)
+ m_stream << '\n';
+ m_stream << "...\n";
+
+ m_pState->UnsetSeparation();
+ m_pState->SwitchState(ES_WAITING_FOR_DOC);
+ }
+
+ // EmitBeginSeq
+ void Emitter::EmitBeginSeq()
+ {
+ if(!good())
+ return;
+
+ // must have a long key if we're emitting a sequence
+ m_pState->StartLongKey();
+
+ PreAtomicWrite();
+
+ EMITTER_STATE curState = m_pState->GetCurState();
+ EMITTER_MANIP flowType = m_pState->GetFlowType(GT_SEQ);
+ if(flowType == Block) {
+ if(curState == ES_WRITING_BLOCK_SEQ_ENTRY ||
+ curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE ||
+ curState == ES_WRITING_DOC
+ ) {
+ if(m_pState->RequiresHardSeparation() || curState != ES_WRITING_DOC) {
+ m_stream << "\n";
+ m_pState->UnsetSeparation();
+ }
+ }
+ m_pState->PushState(ES_WAITING_FOR_BLOCK_SEQ_ENTRY);
+ } else if(flowType == Flow) {
+ EmitSeparationIfNecessary();
+ m_stream << "[";
+ m_pState->PushState(ES_WAITING_FOR_FLOW_SEQ_ENTRY);
+ } else
+ assert(false);
+
+ m_pState->BeginGroup(GT_SEQ);
+ }
+
+ // EmitEndSeq
+ void Emitter::EmitEndSeq()
+ {
+ if(!good())
+ return;
+
+ if(m_pState->GetCurGroupType() != GT_SEQ)
+ return m_pState->SetError(ErrorMsg::UNEXPECTED_END_SEQ);
+
+ EMITTER_STATE curState = m_pState->GetCurState();
+ FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
+ if(flowType == FT_BLOCK) {
+ // Note: block sequences are *not* allowed to be empty, but we convert it
+ // to a flow sequence if it is
+ assert(curState == ES_DONE_WITH_BLOCK_SEQ_ENTRY || curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY);
+ if(curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY) {
+ // Note: only one of these will actually output anything for a given situation
+ EmitSeparationIfNecessary();
+ unsigned curIndent = m_pState->GetCurIndent();
+ m_stream << IndentTo(curIndent);
+
+ m_stream << "[]";
+ }
+ } else if(flowType == FT_FLOW) {
+ // Note: flow sequences are allowed to be empty
+ assert(curState == ES_DONE_WITH_FLOW_SEQ_ENTRY || curState == ES_WAITING_FOR_FLOW_SEQ_ENTRY);
+ m_stream << "]";
+ } else
+ assert(false);
+
+ m_pState->PopState();
+ m_pState->EndGroup(GT_SEQ);
+
+ PostAtomicWrite();
+ }
+
+ // EmitBeginMap
+ void Emitter::EmitBeginMap()
+ {
+ if(!good())
+ return;
+
+ // must have a long key if we're emitting a map
+ m_pState->StartLongKey();
+
+ PreAtomicWrite();
+
+ EMITTER_STATE curState = m_pState->GetCurState();
+ EMITTER_MANIP flowType = m_pState->GetFlowType(GT_MAP);
+ if(flowType == Block) {
+ if(curState == ES_WRITING_BLOCK_SEQ_ENTRY ||
+ curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE ||
+ curState == ES_WRITING_DOC
+ ) {
+ if(m_pState->RequiresHardSeparation() || (curState != ES_WRITING_DOC && curState != ES_WRITING_BLOCK_SEQ_ENTRY)) {
+ m_stream << "\n";
+ m_pState->UnsetSeparation();
+ }
+ }
+ m_pState->PushState(ES_WAITING_FOR_BLOCK_MAP_ENTRY);
+ } else if(flowType == Flow) {
+ EmitSeparationIfNecessary();
+ m_stream << "{";
+ m_pState->PushState(ES_WAITING_FOR_FLOW_MAP_ENTRY);
+ } else
+ assert(false);
+
+ m_pState->BeginGroup(GT_MAP);
+ }
+
+ // EmitEndMap
+ void Emitter::EmitEndMap()
+ {
+ if(!good())
+ return;
+
+ if(m_pState->GetCurGroupType() != GT_MAP)
+ return m_pState->SetError(ErrorMsg::UNEXPECTED_END_MAP);
+
+ EMITTER_STATE curState = m_pState->GetCurState();
+ FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
+ if(flowType == FT_BLOCK) {
+ // Note: block sequences are *not* allowed to be empty, but we convert it
+ // to a flow sequence if it is
+ assert(curState == ES_DONE_WITH_BLOCK_MAP_VALUE || curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY);
+ if(curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY) {
+ // Note: only one of these will actually output anything for a given situation
+ EmitSeparationIfNecessary();
+ unsigned curIndent = m_pState->GetCurIndent();
+ m_stream << IndentTo(curIndent);
+ m_stream << "{}";
+ }
+ } else if(flowType == FT_FLOW) {
+ // Note: flow maps are allowed to be empty
+ assert(curState == ES_DONE_WITH_FLOW_MAP_VALUE || curState == ES_WAITING_FOR_FLOW_MAP_ENTRY);
+ EmitSeparationIfNecessary();
+ m_stream << "}";
+ } else
+ assert(false);
+
+ m_pState->PopState();
+ m_pState->EndGroup(GT_MAP);
+
+ PostAtomicWrite();
+ }
+
+ // EmitKey
+ void Emitter::EmitKey()
+ {
+ if(!good())
+ return;
+
+ EMITTER_STATE curState = m_pState->GetCurState();
+ FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
+ if(curState != ES_WAITING_FOR_BLOCK_MAP_ENTRY && curState != ES_DONE_WITH_BLOCK_MAP_VALUE
+ && curState != ES_WAITING_FOR_FLOW_MAP_ENTRY && curState != ES_DONE_WITH_FLOW_MAP_VALUE)
+ return m_pState->SetError(ErrorMsg::UNEXPECTED_KEY_TOKEN);
+
+ if(flowType == FT_BLOCK) {
+ if(curState == ES_DONE_WITH_BLOCK_MAP_VALUE)
+ m_stream << '\n';
+ unsigned curIndent = m_pState->GetCurIndent();
+ m_stream << IndentTo(curIndent);
+ m_pState->UnsetSeparation();
+ m_pState->SwitchState(ES_WAITING_FOR_BLOCK_MAP_KEY);
+ } else if(flowType == FT_FLOW) {
+ EmitSeparationIfNecessary();
+ if(curState == ES_DONE_WITH_FLOW_MAP_VALUE) {
+ m_stream << ',';
+ m_pState->RequireSoftSeparation();
+ }
+ m_pState->SwitchState(ES_WAITING_FOR_FLOW_MAP_KEY);
+ } else
+ assert(false);
+
+ if(m_pState->GetMapKeyFormat() == LongKey)
+ m_pState->StartLongKey();
+ else if(m_pState->GetMapKeyFormat() == Auto)
+ m_pState->StartSimpleKey();
+ else
+ assert(false);
+ }
+
+ // EmitValue
+ void Emitter::EmitValue()
+ {
+ if(!good())
+ return;
+
+ EMITTER_STATE curState = m_pState->GetCurState();
+ FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
+ if(curState != ES_DONE_WITH_BLOCK_MAP_KEY && curState != ES_DONE_WITH_FLOW_MAP_KEY)
+ return m_pState->SetError(ErrorMsg::UNEXPECTED_VALUE_TOKEN);
+
+ if(flowType == FT_BLOCK) {
+ if(m_pState->CurrentlyInLongKey()) {
+ m_stream << '\n';
+ m_stream << IndentTo(m_pState->GetCurIndent());
+ m_stream << ':';
+ m_pState->RequireSoftSeparation();
+ }
+ m_pState->SwitchState(ES_WAITING_FOR_BLOCK_MAP_VALUE);
+ } else if(flowType == FT_FLOW) {
+ m_pState->SwitchState(ES_WAITING_FOR_FLOW_MAP_VALUE);
+ } else
+ assert(false);
+ }
+
+ // EmitNewline
+ void Emitter::EmitNewline()
+ {
+ if(!good())
+ return;
+
+ if(CanEmitNewline()) {
+ m_stream << '\n';
+ m_pState->UnsetSeparation();
+ }
+ }
+
+ bool Emitter::CanEmitNewline() const
+ {
+ FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
+ if(flowType == FT_BLOCK && m_pState->CurrentlyInLongKey())
+ return true;
+
+ EMITTER_STATE curState = m_pState->GetCurState();
+ return curState != ES_DONE_WITH_BLOCK_MAP_KEY && curState != ES_WAITING_FOR_BLOCK_MAP_VALUE && curState != ES_WRITING_BLOCK_MAP_VALUE;
+ }
+
+ // *******************************************************************************************
+ // overloads of Write
+
+ Emitter& Emitter::Write(const std::string& str)
+ {
+ if(!good())
+ return *this;
+
+ // literal scalars must use long keys
+ if(m_pState->GetStringFormat() == Literal && m_pState->GetCurGroupFlowType() != FT_FLOW)
+ m_pState->StartLongKey();
+
+ PreAtomicWrite();
+ EmitSeparationIfNecessary();
+
+ bool escapeNonAscii = m_pState->GetOutputCharset() == EscapeNonAscii;
+ EMITTER_MANIP strFmt = m_pState->GetStringFormat();
+ FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
+ unsigned curIndent = m_pState->GetCurIndent();
+
+ switch(strFmt) {
+ case Auto:
+ Utils::WriteString(m_stream, str, flowType == FT_FLOW, escapeNonAscii);
+ break;
+ case SingleQuoted:
+ if(!Utils::WriteSingleQuotedString(m_stream, str)) {
+ m_pState->SetError(ErrorMsg::SINGLE_QUOTED_CHAR);
+ return *this;
+ }
+ break;
+ case DoubleQuoted:
+ Utils::WriteDoubleQuotedString(m_stream, str, escapeNonAscii);
+ break;
+ case Literal:
+ if(flowType == FT_FLOW)
+ Utils::WriteString(m_stream, str, flowType == FT_FLOW, escapeNonAscii);
+ else
+ Utils::WriteLiteralString(m_stream, str, curIndent + m_pState->GetIndent());
+ break;
+ default:
+ assert(false);
+ }
+
+ PostAtomicWrite();
+ return *this;
+ }
+
+ void Emitter::PreWriteIntegralType(std::stringstream& str)
+ {
+ PreAtomicWrite();
+ EmitSeparationIfNecessary();
+
+ EMITTER_MANIP intFmt = m_pState->GetIntFormat();
+ switch(intFmt) {
+ case Dec:
+ str << std::dec;
+ break;
+ case Hex:
+ str << "0x";
+ str << std::hex;
+ break;
+ case Oct:
+ str << "0";
+ str << std::oct;
+ break;
+ default:
+ assert(false);
+ }
+ }
+
+ void Emitter::PreWriteStreamable(std::stringstream&)
+ {
+ PreAtomicWrite();
+ EmitSeparationIfNecessary();
+ }
+
+ unsigned Emitter::GetFloatPrecision() const
+ {
+ return m_pState->GetFloatPrecision();
+ }
+
+ unsigned Emitter::GetDoublePrecision() const
+ {
+ return m_pState->GetDoublePrecision();
+ }
+
+ void Emitter::PostWriteIntegralType(const std::stringstream& str)
+ {
+ m_stream << str.str();
+ PostAtomicWrite();
+ }
+
+ void Emitter::PostWriteStreamable(const std::stringstream& str)
+ {
+ m_stream << str.str();
+ PostAtomicWrite();
+ }
+
+ const char *Emitter::ComputeFullBoolName(bool b) const
+ {
+ const EMITTER_MANIP mainFmt = (m_pState->GetBoolLengthFormat() == ShortBool ? YesNoBool : m_pState->GetBoolFormat());
+ const EMITTER_MANIP caseFmt = m_pState->GetBoolCaseFormat();
+ switch(mainFmt) {
+ case YesNoBool:
+ switch(caseFmt) {
+ case UpperCase: return b ? "YES" : "NO";
+ case CamelCase: return b ? "Yes" : "No";
+ case LowerCase: return b ? "yes" : "no";
+ default: break;
+ }
+ break;
+ case OnOffBool:
+ switch(caseFmt) {
+ case UpperCase: return b ? "ON" : "OFF";
+ case CamelCase: return b ? "On" : "Off";
+ case LowerCase: return b ? "on" : "off";
+ default: break;
+ }
+ break;
+ case TrueFalseBool:
+ switch(caseFmt) {
+ case UpperCase: return b ? "TRUE" : "FALSE";
+ case CamelCase: return b ? "True" : "False";
+ case LowerCase: return b ? "true" : "false";
+ default: break;
+ }
+ break;
+ default:
+ break;
+ }
+ return b ? "y" : "n"; // should never get here, but it can't hurt to give these answers
+ }
+
+ Emitter& Emitter::Write(bool b)
+ {
+ if(!good())
+ return *this;
+
+ PreAtomicWrite();
+ EmitSeparationIfNecessary();
+
+ const char *name = ComputeFullBoolName(b);
+ if(m_pState->GetBoolLengthFormat() == ShortBool)
+ m_stream << name[0];
+ else
+ m_stream << name;
+
+ PostAtomicWrite();
+ return *this;
+ }
+
+ Emitter& Emitter::Write(char ch)
+ {
+ if(!good())
+ return *this;
+
+ PreAtomicWrite();
+ EmitSeparationIfNecessary();
+
+ Utils::WriteChar(m_stream, ch);
+
+ PostAtomicWrite();
+ return *this;
+ }
+
+ Emitter& Emitter::Write(const _Alias& alias)
+ {
+ if(!good())
+ return *this;
+
+ PreAtomicWrite();
+ EmitSeparationIfNecessary();
+ if(!Utils::WriteAlias(m_stream, alias.content)) {
+ m_pState->SetError(ErrorMsg::INVALID_ALIAS);
+ return *this;
+ }
+ PostAtomicWrite();
+ return *this;
+ }
+
+ Emitter& Emitter::Write(const _Anchor& anchor)
+ {
+ if(!good())
+ return *this;
+
+ PreAtomicWrite();
+ EmitSeparationIfNecessary();
+ if(!Utils::WriteAnchor(m_stream, anchor.content)) {
+ m_pState->SetError(ErrorMsg::INVALID_ANCHOR);
+ return *this;
+ }
+ m_pState->RequireHardSeparation();
+ // Note: no PostAtomicWrite() because we need another value for this node
+ return *this;
+ }
+
+ Emitter& Emitter::Write(const _Tag& tag)
+ {
+ if(!good())
+ return *this;
+
+ PreAtomicWrite();
+ EmitSeparationIfNecessary();
+
+ bool success = false;
+ if(tag.type == _Tag::Type::Verbatim)
+ success = Utils::WriteTag(m_stream, tag.content, true);
+ else if(tag.type == _Tag::Type::PrimaryHandle)
+ success = Utils::WriteTag(m_stream, tag.content, false);
+ else
+ success = Utils::WriteTagWithPrefix(m_stream, tag.prefix, tag.content);
+
+ if(!success) {
+ m_pState->SetError(ErrorMsg::INVALID_TAG);
+ return *this;
+ }
+
+ m_pState->RequireHardSeparation();
+ // Note: no PostAtomicWrite() because we need another value for this node
+ return *this;
+ }
+
+ void Emitter::EmitKindTag()
+ {
+ Write(LocalTag(""));
+ }
+
+ Emitter& Emitter::Write(const _Comment& comment)
+ {
+ if(!good())
+ return *this;
+
+ if(m_stream.col() > 0)
+ m_stream << Indentation(m_pState->GetPreCommentIndent());
+ Utils::WriteComment(m_stream, comment.content, m_pState->GetPostCommentIndent());
+ m_pState->RequireHardSeparation();
+ m_pState->ForceHardSeparation();
+
+ return *this;
+ }
+
+ Emitter& Emitter::Write(const _Null& /*null*/)
+ {
+ if(!good())
+ return *this;
+
+ PreAtomicWrite();
+ EmitSeparationIfNecessary();
+ m_stream << "~";
+ PostAtomicWrite();
+ return *this;
+ }
+
+ Emitter& Emitter::Write(const Binary& binary)
+ {
+ Write(SecondaryTag("binary"));
+
+ if(!good())
+ return *this;
+
+ PreAtomicWrite();
+ EmitSeparationIfNecessary();
+ Utils::WriteBinary(m_stream, binary);
+ PostAtomicWrite();
+ return *this;
+ }
+}
+