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