Promote Emitter exceptions to asserts or contracts (#246)
* promote emitter exceptions to asserts * convert many emitter asserts to in contracts
This commit is contained in:
parent
d10d2b2981
commit
10356c8bf0
|
@ -35,17 +35,6 @@ import dyaml.tagdirective;
|
||||||
|
|
||||||
package:
|
package:
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception thrown at Emitter errors.
|
|
||||||
*
|
|
||||||
* See_Also:
|
|
||||||
* YAMLException
|
|
||||||
*/
|
|
||||||
class EmitterException : YAMLException
|
|
||||||
{
|
|
||||||
mixin ExceptionCtors;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Stores results of analysis of a scalar, determining e.g. what scalar style to use.
|
//Stores results of analysis of a scalar, determining e.g. what scalar style to use.
|
||||||
struct ScalarAnalysis
|
struct ScalarAnalysis
|
||||||
{
|
{
|
||||||
|
@ -190,7 +179,7 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||||
analysis_.flags.isNull = true;
|
analysis_.flags.isNull = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
///Emit an event. Throws EmitterException on error.
|
///Emit an event.
|
||||||
void emit(Event event) @safe
|
void emit(Event event) @safe
|
||||||
{
|
{
|
||||||
events_.push(event);
|
events_.push(event);
|
||||||
|
@ -205,9 +194,9 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||||
private:
|
private:
|
||||||
///Pop and return the newest state in states_.
|
///Pop and return the newest state in states_.
|
||||||
EmitterFunction popState() @safe
|
EmitterFunction popState() @safe
|
||||||
|
in(states_.data.length > 0,
|
||||||
|
"Emitter: Need to pop a state but there are no states left")
|
||||||
{
|
{
|
||||||
enforce(states_.data.length > 0,
|
|
||||||
new YAMLException("Emitter: Need to pop a state but there are no states left"));
|
|
||||||
const result = states_.data[$-1];
|
const result = states_.data[$-1];
|
||||||
states_.shrinkTo(states_.data.length - 1);
|
states_.shrinkTo(states_.data.length - 1);
|
||||||
return result;
|
return result;
|
||||||
|
@ -220,10 +209,10 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||||
|
|
||||||
///Pop and return the newest indent in indents_.
|
///Pop and return the newest indent in indents_.
|
||||||
int popIndent() @safe
|
int popIndent() @safe
|
||||||
|
in(indents_.data.length > 0,
|
||||||
|
"Emitter: Need to pop an indent level but there" ~
|
||||||
|
" are no indent levels left")
|
||||||
{
|
{
|
||||||
enforce(indents_.data.length > 0,
|
|
||||||
new YAMLException("Emitter: Need to pop an indent level but there" ~
|
|
||||||
" are no indent levels left"));
|
|
||||||
const result = indents_.data[$-1];
|
const result = indents_.data[$-1];
|
||||||
indents_.shrinkTo(indents_.data.length - 1);
|
indents_.shrinkTo(indents_.data.length - 1);
|
||||||
return result;
|
return result;
|
||||||
|
@ -231,8 +220,6 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||||
|
|
||||||
///Write a string to the file/stream.
|
///Write a string to the file/stream.
|
||||||
void writeString(const scope char[] str) @safe
|
void writeString(const scope char[] str) @safe
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
static if(is(CharType == char))
|
static if(is(CharType == char))
|
||||||
{
|
{
|
||||||
|
@ -249,11 +236,6 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||||
copy(buffer, stream_);
|
copy(buffer, stream_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
throw new EmitterException("Unable to write to stream: " ~ e.msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///In some cases, we wait for a few next events before emitting.
|
///In some cases, we wait for a few next events before emitting.
|
||||||
bool needMoreEvents() @safe nothrow
|
bool needMoreEvents() @safe nothrow
|
||||||
|
@ -304,9 +286,8 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||||
|
|
||||||
///Determines if the type of current event is as specified. Throws if no event.
|
///Determines if the type of current event is as specified. Throws if no event.
|
||||||
bool eventTypeIs(in EventID id) const pure @safe
|
bool eventTypeIs(in EventID id) const pure @safe
|
||||||
|
in(!event_.isNull, "Expected an event, but no event is available.")
|
||||||
{
|
{
|
||||||
enforce(!event_.isNull,
|
|
||||||
new EmitterException("Expected an event, but no event is available."));
|
|
||||||
return event_.id == id;
|
return event_.id == id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,9 +299,9 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||||
|
|
||||||
///Handle start of a file/stream.
|
///Handle start of a file/stream.
|
||||||
void expectStreamStart() @safe
|
void expectStreamStart() @safe
|
||||||
|
in(eventTypeIs(EventID.streamStart),
|
||||||
|
"Expected streamStart, but got " ~ event_.idString)
|
||||||
{
|
{
|
||||||
enforce(eventTypeIs(EventID.streamStart),
|
|
||||||
new EmitterException("Expected streamStart, but got " ~ event_.idString));
|
|
||||||
|
|
||||||
writeStreamStart();
|
writeStreamStart();
|
||||||
nextExpected!"expectDocumentStart!(Yes.first)"();
|
nextExpected!"expectDocumentStart!(Yes.first)"();
|
||||||
|
@ -329,17 +310,16 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||||
///Expect nothing, throwing if we still have something.
|
///Expect nothing, throwing if we still have something.
|
||||||
void expectNothing() @safe
|
void expectNothing() @safe
|
||||||
{
|
{
|
||||||
throw new EmitterException("Expected nothing, but got " ~ event_.idString);
|
assert(0, "Expected nothing, but got " ~ event_.idString);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Document handlers.
|
//Document handlers.
|
||||||
|
|
||||||
///Handle start of a document.
|
///Handle start of a document.
|
||||||
void expectDocumentStart(Flag!"first" first)() @safe
|
void expectDocumentStart(Flag!"first" first)() @safe
|
||||||
|
in(eventTypeIs(EventID.documentStart) || eventTypeIs(EventID.streamEnd),
|
||||||
|
"Expected documentStart or streamEnd, but got " ~ event_.idString)
|
||||||
{
|
{
|
||||||
enforce(eventTypeIs(EventID.documentStart) || eventTypeIs(EventID.streamEnd),
|
|
||||||
new EmitterException("Expected documentStart or streamEnd, but got "
|
|
||||||
~ event_.idString));
|
|
||||||
|
|
||||||
if(event_.id == EventID.documentStart)
|
if(event_.id == EventID.documentStart)
|
||||||
{
|
{
|
||||||
|
@ -403,9 +383,9 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||||
|
|
||||||
///Handle end of a document.
|
///Handle end of a document.
|
||||||
void expectDocumentEnd() @safe
|
void expectDocumentEnd() @safe
|
||||||
|
in(eventTypeIs(EventID.documentEnd),
|
||||||
|
"Expected DocumentEnd, but got " ~ event_.idString)
|
||||||
{
|
{
|
||||||
enforce(eventTypeIs(EventID.documentEnd),
|
|
||||||
new EmitterException("Expected DocumentEnd, but got " ~ event_.idString));
|
|
||||||
|
|
||||||
writeIndent();
|
writeIndent();
|
||||||
if(event_.explicitDocument)
|
if(event_.explicitDocument)
|
||||||
|
@ -477,14 +457,14 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new EmitterException("Expected alias_, scalar, sequenceStart or " ~
|
assert(0, "Expected alias_, scalar, sequenceStart or " ~
|
||||||
"mappingStart, but got: " ~ event_.idString);
|
"mappingStart, but got: " ~ event_.idString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
///Handle an alias.
|
///Handle an alias.
|
||||||
void expectAlias() @safe
|
void expectAlias() @safe
|
||||||
|
in(event_.anchor != "", "Anchor is not specified for alias")
|
||||||
{
|
{
|
||||||
enforce(event_.anchor !is null, new EmitterException("Anchor is not specified for alias"));
|
|
||||||
processAnchor("*");
|
processAnchor("*");
|
||||||
nextExpected(popState());
|
nextExpected(popState());
|
||||||
}
|
}
|
||||||
|
@ -811,7 +791,7 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
enforce(tag !is null, new EmitterException("Tag is not specified"));
|
assert(tag != "", "Tag is not specified");
|
||||||
if(preparedTag_ is null){preparedTag_ = prepareTag(tag);}
|
if(preparedTag_ is null){preparedTag_ = prepareTag(tag);}
|
||||||
if(preparedTag_ !is null && preparedTag_ != "")
|
if(preparedTag_ !is null && preparedTag_ != "")
|
||||||
{
|
{
|
||||||
|
@ -865,9 +845,9 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||||
|
|
||||||
///Prepare YAML version string for output.
|
///Prepare YAML version string for output.
|
||||||
static string prepareVersion(const string YAMLVersion) @safe
|
static string prepareVersion(const string YAMLVersion) @safe
|
||||||
|
in(YAMLVersion.split(".")[0] == "1",
|
||||||
|
"Unsupported YAML version: " ~ YAMLVersion)
|
||||||
{
|
{
|
||||||
enforce(YAMLVersion.split(".")[0] == "1",
|
|
||||||
new EmitterException("Unsupported YAML version: " ~ YAMLVersion));
|
|
||||||
return YAMLVersion;
|
return YAMLVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -885,25 +865,17 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||||
|
|
||||||
///Prepare tag directive handle for output.
|
///Prepare tag directive handle for output.
|
||||||
static string prepareTagHandle(const string handle) @safe
|
static string prepareTagHandle(const string handle) @safe
|
||||||
|
in(handle != "", "Tag handle must not be empty")
|
||||||
|
in(handle.drop(1).dropBack(1).all!(c => isAlphaNum(c) || c.among!('-', '_')),
|
||||||
|
"Tag handle contains invalid characters")
|
||||||
{
|
{
|
||||||
enforce(handle !is null && handle != "",
|
|
||||||
new EmitterException("Tag handle must not be empty"));
|
|
||||||
|
|
||||||
if(handle.length > 1) foreach(const dchar c; handle[1 .. $ - 1])
|
|
||||||
{
|
|
||||||
enforce(isAlphaNum(c) || c.among!('-', '_'),
|
|
||||||
new EmitterException("Invalid character: " ~ to!string(c) ~
|
|
||||||
" in tag handle " ~ handle));
|
|
||||||
}
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
///Prepare tag directive prefix for output.
|
///Prepare tag directive prefix for output.
|
||||||
static string prepareTagPrefix(const string prefix) @safe
|
static string prepareTagPrefix(const string prefix) @safe
|
||||||
|
in(prefix != "", "Tag prefix must not be empty")
|
||||||
{
|
{
|
||||||
enforce(prefix !is null && prefix != "",
|
|
||||||
new EmitterException("Tag prefix must not be empty"));
|
|
||||||
|
|
||||||
auto appender = appender!string();
|
auto appender = appender!string();
|
||||||
const int offset = prefix[0] == '!';
|
const int offset = prefix[0] == '!';
|
||||||
size_t start, end;
|
size_t start, end;
|
||||||
|
@ -930,8 +902,8 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||||
|
|
||||||
///Prepare tag for output.
|
///Prepare tag for output.
|
||||||
string prepareTag(in string tag) @safe
|
string prepareTag(in string tag) @safe
|
||||||
|
in(tag != "", "Tag must not be empty")
|
||||||
{
|
{
|
||||||
enforce(tag !is null, new EmitterException("Tag must not be empty"));
|
|
||||||
|
|
||||||
string tagString = tag;
|
string tagString = tag;
|
||||||
if(tagString == "!"){return tagString;}
|
if(tagString == "!"){return tagString;}
|
||||||
|
@ -976,16 +948,10 @@ struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType))
|
||||||
|
|
||||||
///Prepare anchor for output.
|
///Prepare anchor for output.
|
||||||
static string prepareAnchor(const string anchor) @safe
|
static string prepareAnchor(const string anchor) @safe
|
||||||
|
in(anchor != "", "Anchor must not be empty")
|
||||||
|
in(anchor.all!(c => isAlphaNum(c) || c.among!('-', '_')), "Anchor contains invalid characters")
|
||||||
{
|
{
|
||||||
enforce(anchor != "",
|
return anchor;
|
||||||
new EmitterException("Anchor must not be empty"));
|
|
||||||
const str = anchor;
|
|
||||||
foreach(const dchar c; str)
|
|
||||||
{
|
|
||||||
enforce(isAlphaNum(c) || c.among!('-', '_'),
|
|
||||||
new EmitterException("Invalid character: " ~ to!string(c) ~ " in anchor: " ~ str));
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///Analyze specifed scalar and return the analysis result.
|
///Analyze specifed scalar and return the analysis result.
|
||||||
|
|
Loading…
Reference in a new issue