|
|
#include <limits>
#include "emitterstate.h"
#include "yaml-cpp/exceptions.h" // IWYU pragma: keep
namespace YAML { EmitterState::EmitterState() : m_isGood(true), m_lastError{}, // default global manipulators
m_charset(EmitNonAscii), m_strFmt(Auto), m_boolFmt(TrueFalseBool), m_boolLengthFmt(LongBool), m_boolCaseFmt(LowerCase), m_nullFmt(TildeNull), m_intFmt(Dec), m_indent(2), m_preCommentIndent(2), m_postCommentIndent(1), m_seqFmt(Block), m_mapFmt(Block), m_mapKeyFmt(Auto), m_floatPrecision(std::numeric_limits<float>::max_digits10), m_doublePrecision(std::numeric_limits<double>::max_digits10), //
m_modifiedSettings{}, m_globalModifiedSettings{}, m_groups{}, m_curIndent(0), m_hasAnchor(false), m_hasAlias(false), m_hasTag(false), m_hasNonContent(false), m_docCount(0) {}
EmitterState::~EmitterState() = default;
// SetLocalValue
// . We blindly tries to set all possible formatters to this value
// . Only the ones that make sense will be accepted
void EmitterState::SetLocalValue(EMITTER_MANIP value) { SetOutputCharset(value, FmtScope::Local); SetStringFormat(value, FmtScope::Local); SetBoolFormat(value, FmtScope::Local); SetBoolCaseFormat(value, FmtScope::Local); SetBoolLengthFormat(value, FmtScope::Local); SetNullFormat(value, FmtScope::Local); SetIntFormat(value, FmtScope::Local); SetFlowType(GroupType::Seq, value, FmtScope::Local); SetFlowType(GroupType::Map, value, FmtScope::Local); SetMapKeyFormat(value, FmtScope::Local); }
void EmitterState::SetAnchor() { m_hasAnchor = true; }
void EmitterState::SetAlias() { m_hasAlias = true; }
void EmitterState::SetTag() { m_hasTag = true; }
void EmitterState::SetNonContent() { m_hasNonContent = true; }
void EmitterState::SetLongKey() { assert(!m_groups.empty()); if (m_groups.empty()) { return; }
assert(m_groups.back()->type == GroupType::Map); m_groups.back()->longKey = true; }
void EmitterState::ForceFlow() { assert(!m_groups.empty()); if (m_groups.empty()) { return; }
m_groups.back()->flowType = FlowType::Flow; }
void EmitterState::StartedNode() { if (m_groups.empty()) { m_docCount++; } else { m_groups.back()->childCount++; if (m_groups.back()->childCount % 2 == 0) { m_groups.back()->longKey = false; } }
m_hasAnchor = false; m_hasAlias = false; m_hasTag = false; m_hasNonContent = false; }
EmitterNodeType::value EmitterState::NextGroupType( GroupType::value type) const { if (type == GroupType::Seq) { if (GetFlowType(type) == Block) return EmitterNodeType::BlockSeq; return EmitterNodeType::FlowSeq; }
if (GetFlowType(type) == Block) return EmitterNodeType::BlockMap; return EmitterNodeType::FlowMap;
// can't happen
assert(false); return EmitterNodeType::NoType; }
void EmitterState::StartedDoc() { m_hasAnchor = false; m_hasTag = false; m_hasNonContent = false; }
void EmitterState::EndedDoc() { m_hasAnchor = false; m_hasTag = false; m_hasNonContent = false; }
void EmitterState::StartedScalar() { StartedNode(); ClearModifiedSettings(); }
void EmitterState::StartedGroup(GroupType::value type) { StartedNode();
const std::size_t lastGroupIndent = (m_groups.empty() ? 0 : m_groups.back()->indent); m_curIndent += lastGroupIndent;
// TODO: Create move constructors for settings types to simplify transfer
std::unique_ptr<Group> pGroup(new Group(type));
// transfer settings (which last until this group is done)
//
// NB: if pGroup->modifiedSettings == m_modifiedSettings,
// m_modifiedSettings is not changed!
pGroup->modifiedSettings = std::move(m_modifiedSettings);
// set up group
if (GetFlowType(type) == Block) { pGroup->flowType = FlowType::Block; } else { pGroup->flowType = FlowType::Flow; } pGroup->indent = GetIndent();
m_groups.push_back(std::move(pGroup)); }
void EmitterState::EndedGroup(GroupType::value type) { if (m_groups.empty()) { if (type == GroupType::Seq) { return SetError(ErrorMsg::UNEXPECTED_END_SEQ); } return SetError(ErrorMsg::UNEXPECTED_END_MAP); }
if (m_hasTag) { SetError(ErrorMsg::INVALID_TAG); } if (m_hasAnchor) { SetError(ErrorMsg::INVALID_ANCHOR); }
// get rid of the current group
{ std::unique_ptr<Group> pFinishedGroup = std::move(m_groups.back()); m_groups.pop_back(); if (pFinishedGroup->type != type) { return SetError(ErrorMsg::UNMATCHED_GROUP_TAG); } }
// reset old settings
std::size_t lastIndent = (m_groups.empty() ? 0 : m_groups.back()->indent); assert(m_curIndent >= lastIndent); m_curIndent -= lastIndent;
// some global settings that we changed may have been overridden
// by a local setting we just popped, so we need to restore them
m_globalModifiedSettings.restore();
ClearModifiedSettings(); m_hasAnchor = false; m_hasTag = false; m_hasNonContent = false; }
EmitterNodeType::value EmitterState::CurGroupNodeType() const { if (m_groups.empty()) { return EmitterNodeType::NoType; }
return m_groups.back()->NodeType(); }
GroupType::value EmitterState::CurGroupType() const { return m_groups.empty() ? GroupType::NoType : m_groups.back()->type; }
FlowType::value EmitterState::CurGroupFlowType() const { return m_groups.empty() ? FlowType::NoType : m_groups.back()->flowType; }
std::size_t EmitterState::CurGroupIndent() const { return m_groups.empty() ? 0 : m_groups.back()->indent; }
std::size_t EmitterState::CurGroupChildCount() const { return m_groups.empty() ? m_docCount : m_groups.back()->childCount; }
bool EmitterState::CurGroupLongKey() const { return m_groups.empty() ? false : m_groups.back()->longKey; }
std::size_t EmitterState::LastIndent() const { if (m_groups.size() <= 1) { return 0; }
return m_curIndent - m_groups[m_groups.size() - 2]->indent; }
void EmitterState::ClearModifiedSettings() { m_modifiedSettings.clear(); }
void EmitterState::RestoreGlobalModifiedSettings() { m_globalModifiedSettings.restore(); }
bool EmitterState::SetOutputCharset(EMITTER_MANIP value, FmtScope::value scope) { switch (value) { case EmitNonAscii: case EscapeNonAscii: case EscapeAsJson: _Set(m_charset, value, scope); return true; default: return false; } }
bool EmitterState::SetStringFormat(EMITTER_MANIP value, FmtScope::value scope) { switch (value) { case Auto: case SingleQuoted: case DoubleQuoted: case Literal: _Set(m_strFmt, value, scope); return true; default: return false; } }
bool EmitterState::SetBoolFormat(EMITTER_MANIP value, FmtScope::value scope) { switch (value) { case OnOffBool: case TrueFalseBool: case YesNoBool: _Set(m_boolFmt, value, scope); return true; default: return false; } }
bool EmitterState::SetBoolLengthFormat(EMITTER_MANIP value, FmtScope::value scope) { switch (value) { case LongBool: case ShortBool: _Set(m_boolLengthFmt, value, scope); return true; default: return false; } }
bool EmitterState::SetBoolCaseFormat(EMITTER_MANIP value, FmtScope::value scope) { switch (value) { case UpperCase: case LowerCase: case CamelCase: _Set(m_boolCaseFmt, value, scope); return true; default: return false; } }
bool EmitterState::SetNullFormat(EMITTER_MANIP value, FmtScope::value scope) { switch (value) { case LowerNull: case UpperNull: case CamelNull: case TildeNull: _Set(m_nullFmt, value, scope); return true; default: return false; } }
bool EmitterState::SetIntFormat(EMITTER_MANIP value, FmtScope::value scope) { switch (value) { case Dec: case Hex: case Oct: _Set(m_intFmt, value, scope); return true; default: return false; } }
bool EmitterState::SetIndent(std::size_t value, FmtScope::value scope) { if (value <= 1) return false;
_Set(m_indent, value, scope); return true; }
bool EmitterState::SetPreCommentIndent(std::size_t value, FmtScope::value scope) { if (value == 0) return false;
_Set(m_preCommentIndent, value, scope); return true; }
bool EmitterState::SetPostCommentIndent(std::size_t value, FmtScope::value scope) { if (value == 0) return false;
_Set(m_postCommentIndent, value, scope); return true; }
bool EmitterState::SetFlowType(GroupType::value groupType, EMITTER_MANIP value, FmtScope::value scope) { switch (value) { case Block: case Flow: _Set(groupType == GroupType::Seq ? m_seqFmt : m_mapFmt, value, scope); return true; default: return false; } }
EMITTER_MANIP EmitterState::GetFlowType(GroupType::value groupType) const { // force flow style if we're currently in a flow
if (CurGroupFlowType() == FlowType::Flow) return Flow;
// otherwise, go with what's asked of us
return (groupType == GroupType::Seq ? m_seqFmt.get() : m_mapFmt.get()); }
bool EmitterState::SetMapKeyFormat(EMITTER_MANIP value, FmtScope::value scope) { switch (value) { case Auto: case LongKey: _Set(m_mapKeyFmt, value, scope); return true; default: return false; } }
bool EmitterState::SetFloatPrecision(std::size_t value, FmtScope::value scope) { if (value > std::numeric_limits<float>::max_digits10) return false; _Set(m_floatPrecision, value, scope); return true; }
bool EmitterState::SetDoublePrecision(std::size_t value, FmtScope::value scope) { if (value > std::numeric_limits<double>::max_digits10) return false; _Set(m_doublePrecision, value, scope); return true; } } // namespace YAML
|