Simplified some Emitter code.

This commit is contained in:
kiith-sa 2012-09-14 01:16:05 +02:00
parent 58fc17197b
commit 19d88d156a

View file

@ -100,14 +100,20 @@ struct Emitter
///Level of nesting in flow context. If 0, we're in block context. ///Level of nesting in flow context. If 0, we're in block context.
uint flowLevel_ = 0; uint flowLevel_ = 0;
///Are we in the root node of a document? /// Describes context (where we are in the document).
bool rootContext_; enum Context
///Are we in a sequence? {
bool sequenceContext_; /// Root node of a document.
///Are we in a mapping? Root,
bool mappingContext_; /// Sequence.
///Are we in a simple key? Sequence,
bool simpleKeyContext_; /// Mapping.
MappingNoSimpleKey,
/// Mapping, in a simple key.
MappingSimpleKey
}
/// Current context.
Context context_;
///Characteristics of the last emitted character: ///Characteristics of the last emitted character:
@ -159,8 +165,8 @@ struct Emitter
* indent = Indentation width. * indent = Indentation width.
* lineBreak = Line break character/s. * lineBreak = Line break character/s.
*/ */
this(Stream stream, in bool canonical, in int indent, in int width, this(Stream stream, const bool canonical, const int indent, const int width,
in LineBreak lineBreak) @trusted nothrow const LineBreak lineBreak) @trusted nothrow
in{assert(stream.writeable, "Can't emit YAML to a non-writable stream");} in{assert(stream.writeable, "Can't emit YAML to a non-writable stream");}
body body
{ {
@ -291,7 +297,7 @@ struct Emitter
} }
///Increase indentation level. ///Increase indentation level.
void increaseIndent(in bool flow = false, in bool indentless = false) @trusted void increaseIndent(const Flag!"flow" flow = No.flow, const bool indentless = false) @trusted
{ {
indents_ ~= indent_; indents_ ~= indent_;
if(indent_ == -1) if(indent_ == -1)
@ -350,7 +356,7 @@ struct Emitter
auto tagDirectives = event_.tagDirectives; auto tagDirectives = event_.tagDirectives;
if(openEnded_ && (YAMLVersion !is null || tagDirectives !is null)) if(openEnded_ && (YAMLVersion !is null || tagDirectives !is null))
{ {
writeIndicator("...", true); writeIndicator("...", Yes.needWhitespace);
writeIndent(); writeIndent();
} }
@ -387,16 +393,16 @@ struct Emitter
if(!implicit) if(!implicit)
{ {
writeIndent(); writeIndent();
writeIndicator("---", true); writeIndicator("---", Yes.needWhitespace);
if(canonical_){writeIndent();} if(canonical_){writeIndent();}
} }
state_ = &expectDocumentRoot; state_ = &expectRootNode;
} }
else if(event_.id == EventID.StreamEnd) else if(event_.id == EventID.StreamEnd)
{ {
if(openEnded_) if(openEnded_)
{ {
writeIndicator("...", true); writeIndicator("...", Yes.needWhitespace);
writeIndent(); writeIndent();
} }
writeStreamEnd(); writeStreamEnd();
@ -413,7 +419,7 @@ struct Emitter
writeIndent(); writeIndent();
if(event_.explicitDocument) if(event_.explicitDocument)
{ {
writeIndicator("...", true); writeIndicator("...", Yes.needWhitespace);
writeIndent(); writeIndent();
} }
stream_.flush(); stream_.flush();
@ -421,20 +427,30 @@ struct Emitter
} }
///Handle the root node of a document. ///Handle the root node of a document.
void expectDocumentRoot() @trusted void expectRootNode() @trusted
{ {
states_ ~= &expectDocumentEnd; states_ ~= &expectDocumentEnd;
expectNode(true); expectNode(Context.Root);
} }
///Handle a new node. Parameters determine context. ///Handle a mapping node.
void expectNode(in bool root = false, in bool sequence = false, //
in bool mapping = false, in bool simpleKey = false) @trusted //Params: simpleKey = Are we in a simple key?
void expectMappingNode(const bool simpleKey = false)
{ {
rootContext_ = root; expectNode(simpleKey ? Context.MappingSimpleKey : Context.MappingNoSimpleKey);
sequenceContext_ = sequence; }
mappingContext_ = mapping;
simpleKeyContext_ = simpleKey; ///Handle a sequence node.
void expectSequenceNode()
{
expectNode(Context.Sequence);
}
///Handle a new node. Context specifies where in the document we are.
void expectNode(const Context context) @trusted
{
context_ = context;
const flowCollection = event_.collectionStyle == CollectionStyle.Flow; const flowCollection = event_.collectionStyle == CollectionStyle.Flow;
@ -475,7 +491,6 @@ struct Emitter
"MappingStart, but got: " ~ event_.idString); "MappingStart, but got: " ~ event_.idString);
} }
} }
///Handle an alias. ///Handle an alias.
void expectAlias() @trusted void expectAlias() @trusted
{ {
@ -487,7 +502,7 @@ struct Emitter
///Handle a scalar. ///Handle a scalar.
void expectScalar() @trusted void expectScalar() @trusted
{ {
increaseIndent(true); increaseIndent(Yes.flow);
processScalar(); processScalar();
indent_ = popIndent(); indent_ = popIndent();
state_ = popState(); state_ = popState();
@ -498,9 +513,9 @@ struct Emitter
///Handle a flow sequence. ///Handle a flow sequence.
void expectFlowSequence() @trusted void expectFlowSequence() @trusted
{ {
writeIndicator("[", true, true); writeIndicator("[", Yes.needWhitespace, Yes.whitespace);
++flowLevel_; ++flowLevel_;
increaseIndent(true); increaseIndent(Yes.flow);
state_ = &expectFlowSequenceItem!true; state_ = &expectFlowSequenceItem!true;
} }
@ -513,17 +528,17 @@ struct Emitter
--flowLevel_; --flowLevel_;
static if(!first) if(canonical_) static if(!first) if(canonical_)
{ {
writeIndicator(",", false); writeIndicator(",", No.needWhitespace);
writeIndent(); writeIndent();
} }
writeIndicator("]", false); writeIndicator("]", No.needWhitespace);
state_ = popState(); state_ = popState();
return; return;
} }
static if(!first){writeIndicator(",", false);} static if(!first){writeIndicator(",", No.needWhitespace);}
if(canonical_ || column_ > bestWidth_){writeIndent();} if(canonical_ || column_ > bestWidth_){writeIndent();}
states_ ~= &expectFlowSequenceItem!false; states_ ~= &expectFlowSequenceItem!false;
expectNode(false, true); expectSequenceNode();
} }
//Flow mapping handlers. //Flow mapping handlers.
@ -531,9 +546,9 @@ struct Emitter
///Handle a flow mapping. ///Handle a flow mapping.
void expectFlowMapping() @trusted void expectFlowMapping() @trusted
{ {
writeIndicator("{", true, true); writeIndicator("{", Yes.needWhitespace, Yes.whitespace);
++flowLevel_; ++flowLevel_;
increaseIndent(true); increaseIndent(Yes.flow);
state_ = &expectFlowMappingKey!true; state_ = &expectFlowMappingKey!true;
} }
@ -546,43 +561,43 @@ struct Emitter
--flowLevel_; --flowLevel_;
static if (!first) if(canonical_) static if (!first) if(canonical_)
{ {
writeIndicator(",", false); writeIndicator(",", No.needWhitespace);
writeIndent(); writeIndent();
} }
writeIndicator("}", false); writeIndicator("}", No.needWhitespace);
state_ = popState(); state_ = popState();
return; return;
} }
static if(!first){writeIndicator(",", false);} static if(!first){writeIndicator(",", No.needWhitespace);}
if(canonical_ || column_ > bestWidth_){writeIndent();} if(canonical_ || column_ > bestWidth_){writeIndent();}
if(!canonical_ && checkSimpleKey()) if(!canonical_ && checkSimpleKey())
{ {
states_ ~= &expectFlowMappingSimpleValue; states_ ~= &expectFlowMappingSimpleValue;
expectNode(false, false, true, true); expectMappingNode(true);
return; return;
} }
writeIndicator("?", true); writeIndicator("?", Yes.needWhitespace);
states_ ~= &expectFlowMappingValue; states_ ~= &expectFlowMappingValue;
expectNode(false, false, true); expectMappingNode();
} }
///Handle a simple value in a flow mapping. ///Handle a simple value in a flow mapping.
void expectFlowMappingSimpleValue() @trusted void expectFlowMappingSimpleValue() @trusted
{ {
writeIndicator(":", false); writeIndicator(":", No.needWhitespace);
states_ ~= &expectFlowMappingKey!false; states_ ~= &expectFlowMappingKey!false;
expectNode(false, false, true); expectMappingNode();
} }
///Handle a complex value in a flow mapping. ///Handle a complex value in a flow mapping.
void expectFlowMappingValue() @trusted void expectFlowMappingValue() @trusted
{ {
if(canonical_ || column_ > bestWidth_){writeIndent();} if(canonical_ || column_ > bestWidth_){writeIndent();}
writeIndicator(":", true); writeIndicator(":", Yes.needWhitespace);
states_ ~= &expectFlowMappingKey!false; states_ ~= &expectFlowMappingKey!false;
expectNode(false, false, true); expectMappingNode();
} }
//Block sequence handlers. //Block sequence handlers.
@ -590,8 +605,9 @@ struct Emitter
///Handle a block sequence. ///Handle a block sequence.
void expectBlockSequence() @safe void expectBlockSequence() @safe
{ {
const indentless = mappingContext_ && !indentation_; const indentless = (context_ == Context.MappingNoSimpleKey ||
increaseIndent(false, indentless); context_ == Context.MappingSimpleKey) && !indentation_;
increaseIndent(No.flow, indentless);
state_ = &expectBlockSequenceItem!true; state_ = &expectBlockSequenceItem!true;
} }
@ -606,9 +622,9 @@ struct Emitter
} }
writeIndent(); writeIndent();
writeIndicator("-", true, false, true); writeIndicator("-", Yes.needWhitespace, No.whitespace, Yes.indentation);
states_ ~= &expectBlockSequenceItem!false; states_ ~= &expectBlockSequenceItem!false;
expectNode(false, true); expectSequenceNode();
} }
//Block mapping handlers. //Block mapping handlers.
@ -616,7 +632,7 @@ struct Emitter
///Handle a block mapping. ///Handle a block mapping.
void expectBlockMapping() @safe void expectBlockMapping() @safe
{ {
increaseIndent(false); increaseIndent(No.flow);
state_ = &expectBlockMappingKey!true; state_ = &expectBlockMappingKey!true;
} }
@ -634,30 +650,30 @@ struct Emitter
if(checkSimpleKey()) if(checkSimpleKey())
{ {
states_ ~= &expectBlockMappingSimpleValue; states_ ~= &expectBlockMappingSimpleValue;
expectNode(false, false, true, true); expectMappingNode(true);
return; return;
} }
writeIndicator("?", true, false, true); writeIndicator("?", Yes.needWhitespace, No.whitespace, Yes.indentation);
states_ ~= &expectBlockMappingValue; states_ ~= &expectBlockMappingValue;
expectNode(false, false, true); expectMappingNode();
} }
///Handle a simple value in a block mapping. ///Handle a simple value in a block mapping.
void expectBlockMappingSimpleValue() @trusted void expectBlockMappingSimpleValue() @trusted
{ {
writeIndicator(":", false); writeIndicator(":", No.needWhitespace);
states_ ~= &expectBlockMappingKey!false; states_ ~= &expectBlockMappingKey!false;
expectNode(false, false, true); expectMappingNode();
} }
///Handle a complex value in a block mapping. ///Handle a complex value in a block mapping.
void expectBlockMappingValue() @trusted void expectBlockMappingValue() @trusted
{ {
writeIndent(); writeIndent();
writeIndicator(":", true, false, true); writeIndicator(":", Yes.needWhitespace, No.whitespace, Yes.indentation);
states_ ~= &expectBlockMappingKey!false; states_ ~= &expectBlockMappingKey!false;
expectNode(false, false, true); expectMappingNode();
} }
//Checkers. //Checkers.
@ -738,13 +754,14 @@ struct Emitter
style_ = chooseScalarStyle(); style_ = chooseScalarStyle();
} }
//if(analysis_.flags.multiline && !simpleKeyContext_ && //if(analysis_.flags.multiline && (context_ != Context.MappingSimpleKey) &&
// ([ScalarStyle.Invalid, ScalarStyle.Plain, ScalarStyle.SingleQuoted, ScalarStyle.DoubleQuoted) // ([ScalarStyle.Invalid, ScalarStyle.Plain, ScalarStyle.SingleQuoted, ScalarStyle.DoubleQuoted)
// .canFind(style_)) // .canFind(style_))
//{ //{
// writeIndent(); // writeIndent();
//} //}
auto writer = ScalarWriter(this, analysis_.scalar, !simpleKeyContext_); auto writer = ScalarWriter(this, analysis_.scalar,
context_ != Context.MappingSimpleKey);
with(writer) final switch(style_) with(writer) final switch(style_)
{ {
case ScalarStyle.Invalid: assert(false); case ScalarStyle.Invalid: assert(false);
@ -772,7 +789,7 @@ struct Emitter
} }
if(preparedAnchor_ !is null && preparedAnchor_ != "") if(preparedAnchor_ !is null && preparedAnchor_ != "")
{ {
writeIndicator(indicator, true); writeIndicator(indicator, Yes.needWhitespace);
writeString(preparedAnchor_); writeString(preparedAnchor_);
} }
preparedAnchor_ = null; preparedAnchor_ = null;
@ -808,7 +825,7 @@ struct Emitter
if(preparedTag_ is null){preparedTag_ = prepareTag(tag);} if(preparedTag_ is null){preparedTag_ = prepareTag(tag);}
if(preparedTag_ !is null && preparedTag_ != "") if(preparedTag_ !is null && preparedTag_ != "")
{ {
writeIndicator(preparedTag_, true); writeIndicator(preparedTag_, Yes.needWhitespace);
} }
preparedTag_ = null; preparedTag_ = null;
} }
@ -827,7 +844,7 @@ struct Emitter
const allowPlain = flowLevel_ > 0 ? analysis_.flags.allowFlowPlain const allowPlain = flowLevel_ > 0 ? analysis_.flags.allowFlowPlain
: analysis_.flags.allowBlockPlain; : analysis_.flags.allowBlockPlain;
//simple empty or multiline scalars can't be written in plain style //simple empty or multiline scalars can't be written in plain style
const simpleNonPlain = simpleKeyContext_ && const simpleNonPlain = (context_ == Context.MappingSimpleKey) &&
(analysis_.flags.empty || analysis_.flags.multiline); (analysis_.flags.empty || analysis_.flags.multiline);
if(doubleQuoted || canonical_) if(doubleQuoted || canonical_)
@ -840,7 +857,7 @@ struct Emitter
return ScalarStyle.Plain; return ScalarStyle.Plain;
} }
if(block && flowLevel_ == 0 && !simpleKeyContext_ && if(block && flowLevel_ == 0 && context_ != Context.MappingSimpleKey &&
analysis_.flags.allowBlock) analysis_.flags.allowBlock)
{ {
return style; return style;
@ -848,7 +865,7 @@ struct Emitter
if((invalidOrPlain || singleQuoted) && if((invalidOrPlain || singleQuoted) &&
analysis_.flags.allowSingleQuoted && analysis_.flags.allowSingleQuoted &&
!(simpleKeyContext_ && analysis_.flags.multiline)) !(context_ == Context.MappingSimpleKey && analysis_.flags.multiline))
{ {
return ScalarStyle.SingleQuoted; return ScalarStyle.SingleQuoted;
} }
@ -970,7 +987,7 @@ struct Emitter
} }
///Prepare anchor for output. ///Prepare anchor for output.
static string prepareAnchor(in Anchor anchor) @trusted static string prepareAnchor(const Anchor anchor) @trusted
{ {
enforce(!anchor.isNull() && anchor.get != "", enforce(!anchor.isNull() && anchor.get != "",
new Error("Anchor must not be empty")); new Error("Anchor must not be empty"));
@ -1179,13 +1196,15 @@ struct Emitter
void writeStreamEnd() @system {stream_.flush();} void writeStreamEnd() @system {stream_.flush();}
///Write an indicator (e.g. ":", "[", ">", etc.). ///Write an indicator (e.g. ":", "[", ">", etc.).
void writeIndicator(const string indicator, in bool needWhitespace, void writeIndicator(const string indicator,
in bool whitespace = false, in bool indentation = false) @system const Flag!"needWhitespace" needWhitespace,
const Flag!"whitespace" whitespace = No.whitespace,
const Flag!"indentation" indentation = No.indentation) @system
{ {
const bool prefixSpace = !whitespace_ && needWhitespace; const bool prefixSpace = !whitespace_ && needWhitespace;
whitespace_ = whitespace; whitespace_ = whitespace;
indentation_ = indentation_ && indentation; indentation_ = indentation_ && indentation;
openEnded_ = false; openEnded_ = false;
column_ += indicator.length; column_ += indicator.length;
if(prefixSpace) if(prefixSpace)
{ {
@ -1290,7 +1309,7 @@ struct ScalarWriter
public: public:
///Construct a ScalarWriter using emitter to output text. ///Construct a ScalarWriter using emitter to output text.
this(ref Emitter emitter, string text, in bool split = true) @trusted nothrow this(ref Emitter emitter, string text, const bool split = true) @trusted nothrow
{ {
emitter_ = &emitter; emitter_ = &emitter;
text_ = text; text_ = text;
@ -1306,7 +1325,7 @@ struct ScalarWriter
///Write text as single quoted scalar. ///Write text as single quoted scalar.
void writeSingleQuoted() @system void writeSingleQuoted() @system
{ {
emitter_.writeIndicator("\'", true); emitter_.writeIndicator("\'", Yes.needWhitespace);
spaces_ = breaks_ = false; spaces_ = breaks_ = false;
resetTextPosition(); resetTextPosition();
@ -1350,14 +1369,14 @@ struct ScalarWriter
updateBreaks(c, Flag!"UpdateSpaces".yes); updateBreaks(c, Flag!"UpdateSpaces".yes);
}while(endByte_ < text_.length); }while(endByte_ < text_.length);
emitter_.writeIndicator("\'", false); emitter_.writeIndicator("\'", No.needWhitespace);
} }
///Write text as double quoted scalar. ///Write text as double quoted scalar.
void writeDoubleQuoted() @system void writeDoubleQuoted() @system
{ {
resetTextPosition(); resetTextPosition();
emitter_.writeIndicator("\"", true); emitter_.writeIndicator("\"", Yes.needWhitespace);
do do
{ {
const dchar c = nextChar(); const dchar c = nextChar();
@ -1412,7 +1431,7 @@ struct ScalarWriter
} }
} }
}while(endByte_ < text_.length); }while(endByte_ < text_.length);
emitter_.writeIndicator("\"", false); emitter_.writeIndicator("\"", No.needWhitespace);
} }
///Write text as folded block scalar. ///Write text as folded block scalar.
@ -1491,7 +1510,7 @@ struct ScalarWriter
///Write text as plain scalar. ///Write text as plain scalar.
void writePlain() @system void writePlain() @system
{ {
if(emitter_.rootContext_){emitter_.openEnded_ = true;} if(emitter_.context_ == Emitter.Context.Root){emitter_.openEnded_ = true;}
if(text_ == ""){return;} if(text_ == ""){return;}
if(!emitter_.whitespace_) if(!emitter_.whitespace_)
{ {
@ -1597,12 +1616,12 @@ struct ScalarWriter
} }
///Initialize for block scalar writing with specified indicator. ///Initialize for block scalar writing with specified indicator.
void initBlock(in char indicator) @system void initBlock(const char indicator) @system
{ {
char[4] hints; char[4] hints;
hints[0] = indicator; hints[0] = indicator;
const hintsLength = 1 + determineBlockHints(hints[1 .. $], emitter_.bestIndent_); const hintsLength = 1 + determineBlockHints(hints[1 .. $], emitter_.bestIndent_);
emitter_.writeIndicator(cast(string)hints[0 .. hintsLength], true); emitter_.writeIndicator(cast(string)hints[0 .. hintsLength], Yes.needWhitespace);
if(hints.length > 0 && hints[$ - 1] == '+') if(hints.length > 0 && hints[$ - 1] == '+')
{ {
emitter_.openEnded_ = true; emitter_.openEnded_ = true;
@ -1611,7 +1630,7 @@ struct ScalarWriter
} }
///Write out the current text range. ///Write out the current text range.
void writeCurrentRange(in Flag!"UpdateColumn" updateColumn) @system void writeCurrentRange(const Flag!"UpdateColumn" updateColumn) @system
{ {
emitter_.writeString(text_[startByte_ .. endByte_]); emitter_.writeString(text_[startByte_ .. endByte_]);
if(updateColumn){emitter_.column_ += endChar_ - startChar_;} if(updateColumn){emitter_.column_ += endChar_ - startChar_;}
@ -1641,7 +1660,7 @@ struct ScalarWriter
} }
///Write indentation, optionally resetting whitespace/indentation flags. ///Write indentation, optionally resetting whitespace/indentation flags.
void writeIndent(in Flag!"ResetSpace" resetSpace) @system void writeIndent(const Flag!"ResetSpace" resetSpace) @system
{ {
emitter_.writeIndent(); emitter_.writeIndent();
if(resetSpace) if(resetSpace)
@ -1658,7 +1677,7 @@ struct ScalarWriter
} }
///Update the line breaks_ flag, optionally updating the spaces_ flag. ///Update the line breaks_ flag, optionally updating the spaces_ flag.
void updateBreaks(in dchar c, in Flag!"UpdateSpaces" updateSpaces) pure @trusted void updateBreaks(in dchar c, const Flag!"UpdateSpaces" updateSpaces) pure @trusted
{ {
if(c == dcharNone){return;} if(c == dcharNone){return;}
breaks_ = newlineSearch_.canFind(c); breaks_ = newlineSearch_.canFind(c);