// 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); }
Emitter& Emitter::Write(int i) { if(!good()) return *this; PreAtomicWrite(); EmitSeparationIfNecessary(); EMITTER_MANIP intFmt = m_pState->GetIntFormat(); std::stringstream str; switch(intFmt) { case Dec: str << std::dec; break; case Hex: str << std::hex; break; case Oct: str << std::oct; break; default: assert(false); } str << i; m_stream << str.str(); PostAtomicWrite(); return *this; }
// 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 ) { 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); }
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; }
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; }
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 _Tag& tag) { if(!good()) return *this; PreAtomicWrite(); EmitSeparationIfNecessary(); if(!Utils::WriteTag(m_stream, tag.content)) { m_pState->SetError(ErrorMsg::INVALID_TAG); return *this; } m_pState->RequireSeparation(); // Note: no PostAtomicWrite() because we need another value for this node return *this; }
Emitter& Emitter::Write(double d) { if(!good()) return *this; PreAtomicWrite(); EmitSeparationIfNecessary(); std::stringstream str; str << d; m_stream << str.str(); 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(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(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 << std::hex; break; case Oct: str << std::oct; break; default: assert(false); } }
Emitter& Emitter::Write(bool b) { if(!good()) return *this; PreAtomicWrite(); EmitSeparationIfNecessary(); // set up all possible bools to write struct BoolName { std::string trueName, falseName; }; struct BoolFormatNames { BoolName upper, lower, camel; }; struct BoolTypes { BoolFormatNames yesNo, trueFalse, onOff; }; static const BoolTypes boolTypes = { { { "YES", "NO" }, { "yes", "no" }, { "Yes", "No" } }, { { "TRUE", "FALSE" }, { "true", "false" }, { "True", "False" } }, { { "ON", "OFF" }, { "on", "off" }, { "On", "Off" } } }; // select the right one EMITTER_MANIP boolFmt = m_pState->GetBoolFormat(); EMITTER_MANIP boolLengthFmt = m_pState->GetBoolLengthFormat(); EMITTER_MANIP boolCaseFmt = m_pState->GetBoolCaseFormat(); const BoolFormatNames& fmtNames = (boolFmt == YesNoBool ? boolTypes.yesNo : boolFmt == TrueFalseBool ? boolTypes.trueFalse : boolTypes.onOff); const BoolName& boolName = (boolCaseFmt == UpperCase ? fmtNames.upper : boolCaseFmt == LowerCase ? fmtNames.lower : fmtNames.camel); const std::string& name = (b ? boolName.trueName : boolName.falseName); // and say it! // TODO: should we disallow writing OnOffBool with ShortBool? (it'll just print "o" for both, which is silly) if(boolLengthFmt == ShortBool) m_stream << name[0]; else m_stream << name; PostAtomicWrite(); return *this; }
void Emitter::PreWriteStreamable(std::stringstream& str) { PreAtomicWrite(); EmitSeparationIfNecessary(); str.precision(15); }
// 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_stream << "---"; m_pState->RequireSeparation(); m_pState->SwitchState(ES_WRITING_DOC); return true; case ES_WRITING_DOC: return true; // block sequence case ES_WAITING_FOR_BLOCK_SEQ_ENTRY: m_stream << IndentTo(curIndent) << "-"; m_pState->RequireSeparation(); 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: m_stream << ','; m_pState->RequireSeparation(); 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->RequireSeparation(); } 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: if(m_pState->CurrentlyInLongKey()) m_stream << IndentTo(curIndent); m_stream << ':'; m_pState->RequireSeparation(); 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: m_pState->SwitchState(ES_WRITING_FLOW_MAP_KEY); if(m_pState->CurrentlyInLongKey()) { EmitSeparationIfNecessary(); m_stream << '?'; m_pState->RequireSeparation(); } 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: m_stream << ':'; m_pState->RequireSeparation(); 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; }
void Emitter::PreWriteStreamable(std::stringstream&) { PreAtomicWrite(); EmitSeparationIfNecessary(); }