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:
Cameron Ross 2019-04-17 22:09:42 -02:30 committed by Basile-z
parent d10d2b2981
commit 10356c8bf0

View file

@ -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.