Merge pull request #241 from Herringway/exception-fixes
Some Exception-related fixes merged-on-behalf-of: Basile-z <Basile-z@users.noreply.github.com>
This commit is contained in:
commit
a538662c7e
|
@ -38,7 +38,7 @@ class ConstructorException : YAMLException
|
||||||
/// Params: msg = Error message.
|
/// Params: msg = Error message.
|
||||||
/// start = Start position of the error context.
|
/// start = Start position of the error context.
|
||||||
/// end = End position of the error context.
|
/// end = End position of the error context.
|
||||||
this(string msg, Mark start, Mark end, string file = __FILE__, int line = __LINE__)
|
this(string msg, Mark start, Mark end, string file = __FILE__, size_t line = __LINE__)
|
||||||
@safe pure nothrow
|
@safe pure nothrow
|
||||||
{
|
{
|
||||||
super(msg ~ "\nstart: " ~ start.toString() ~ "\nend: " ~ end.toString(),
|
super(msg ~ "\nstart: " ~ start.toString() ~ "\nend: " ~ end.toString(),
|
||||||
|
|
|
@ -33,7 +33,7 @@ class NodeException : YAMLException
|
||||||
//
|
//
|
||||||
// Params: msg = Error message.
|
// Params: msg = Error message.
|
||||||
// start = Start position of the node.
|
// start = Start position of the node.
|
||||||
this(string msg, Mark start, string file = __FILE__, int line = __LINE__)
|
this(string msg, Mark start, string file = __FILE__, size_t line = __LINE__)
|
||||||
@safe
|
@safe
|
||||||
{
|
{
|
||||||
super(msg ~ "\nNode at: " ~ start.toString(), file, line);
|
super(msg ~ "\nNode at: " ~ start.toString(), file, line);
|
||||||
|
|
|
@ -34,7 +34,7 @@ package:
|
||||||
///Exception thrown at Reader errors.
|
///Exception thrown at Reader errors.
|
||||||
class ReaderException : YAMLException
|
class ReaderException : YAMLException
|
||||||
{
|
{
|
||||||
this(string msg, string file = __FILE__, int line = __LINE__)
|
this(string msg, string file = __FILE__, size_t line = __LINE__)
|
||||||
@safe pure nothrow
|
@safe pure nothrow
|
||||||
{
|
{
|
||||||
super("Reader error: " ~ msg, file, line);
|
super("Reader error: " ~ msg, file, line);
|
||||||
|
|
|
@ -150,25 +150,6 @@ struct Scanner
|
||||||
/// Possible simple keys indexed by flow levels.
|
/// Possible simple keys indexed by flow levels.
|
||||||
SimpleKey[] possibleSimpleKeys_;
|
SimpleKey[] possibleSimpleKeys_;
|
||||||
|
|
||||||
|
|
||||||
/// Set on error by nothrow/@nogc inner functions along with errorData_.
|
|
||||||
///
|
|
||||||
/// Non-nothrow/GC-using caller functions can then throw an exception using
|
|
||||||
/// data stored in errorData_.
|
|
||||||
bool error_;
|
|
||||||
|
|
||||||
/// Data for the exception to throw if error_ is true.
|
|
||||||
MarkedYAMLExceptionData errorData_;
|
|
||||||
|
|
||||||
/// Error messages can be built in this buffer without using the GC.
|
|
||||||
///
|
|
||||||
/// ScannerException (MarkedYAMLException) copies string data passed to its
|
|
||||||
/// constructor so it's safe to use slices of this buffer as parameters for
|
|
||||||
/// exceptions that may outlive the Scanner. The GC allocation when creating the
|
|
||||||
/// error message is removed, but the allocation when creating an exception is
|
|
||||||
/// not.
|
|
||||||
char[256] msgBuffer_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Construct a Scanner using specified Reader.
|
/// Construct a Scanner using specified Reader.
|
||||||
this(Reader reader) @safe nothrow
|
this(Reader reader) @safe nothrow
|
||||||
|
@ -203,45 +184,11 @@ struct Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Build an error message in msgBuffer_ and return it as a string.
|
|
||||||
string buildMsg(S ...)(S args)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
return text(args);
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Most scanning error messages have the same format; so build them with this
|
/// Most scanning error messages have the same format; so build them with this
|
||||||
/// function.
|
/// function.
|
||||||
string expected(T)(string expected, T found)
|
string expected(T)(string expected, T found)
|
||||||
{
|
{
|
||||||
return buildMsg("expected ", expected, ", but found ", found);
|
return text("expected ", expected, ", but found ", found);
|
||||||
}
|
|
||||||
|
|
||||||
/// If error_ is true, throws a ScannerException constructed from errorData_ and
|
|
||||||
/// sets error_ to false.
|
|
||||||
void throwIfError() @safe pure
|
|
||||||
{
|
|
||||||
if(!error_) { return; }
|
|
||||||
error_ = false;
|
|
||||||
throw new ScannerException(errorData_);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Called by internal nothrow/@nogc methods to set an error to be thrown by
|
|
||||||
/// their callers.
|
|
||||||
///
|
|
||||||
/// See_Also: dyaml.exception.MarkedYamlException
|
|
||||||
void error(string context, const Mark contextMark, string problem,
|
|
||||||
const Mark problemMark) @safe pure nothrow @nogc
|
|
||||||
{
|
|
||||||
assert(error_ == false,
|
|
||||||
"Setting an error when there already is a not yet thrown error");
|
|
||||||
error_ = true;
|
|
||||||
errorData_ = MarkedYAMLExceptionData(context, contextMark, problem, problemMark);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine whether or not we need to fetch more tokens before peeking/getting a token.
|
/// Determine whether or not we need to fetch more tokens before peeking/getting a token.
|
||||||
|
@ -462,7 +409,6 @@ struct Scanner
|
||||||
allowSimpleKey_ = false;
|
allowSimpleKey_ = false;
|
||||||
|
|
||||||
auto directive = scanDirective();
|
auto directive = scanDirective();
|
||||||
throwIfError();
|
|
||||||
tokens_.push(directive);
|
tokens_.push(directive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -646,7 +592,6 @@ struct Scanner
|
||||||
allowSimpleKey_ = false;
|
allowSimpleKey_ = false;
|
||||||
|
|
||||||
auto anchor = scanAnchor(id);
|
auto anchor = scanAnchor(id);
|
||||||
throwIfError();
|
|
||||||
tokens_.push(anchor);
|
tokens_.push(anchor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -663,7 +608,6 @@ struct Scanner
|
||||||
allowSimpleKey_ = false;
|
allowSimpleKey_ = false;
|
||||||
|
|
||||||
tokens_.push(scanTag());
|
tokens_.push(scanTag());
|
||||||
throwIfError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add block SCALAR token.
|
/// Add block SCALAR token.
|
||||||
|
@ -676,7 +620,6 @@ struct Scanner
|
||||||
allowSimpleKey_ = true;
|
allowSimpleKey_ = true;
|
||||||
|
|
||||||
auto blockScalar = scanBlockScalar(style);
|
auto blockScalar = scanBlockScalar(style);
|
||||||
throwIfError();
|
|
||||||
tokens_.push(blockScalar);
|
tokens_.push(blockScalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -694,7 +637,6 @@ struct Scanner
|
||||||
|
|
||||||
// Scan and add SCALAR.
|
// Scan and add SCALAR.
|
||||||
auto scalar = scanFlowScalar(quotes);
|
auto scalar = scanFlowScalar(quotes);
|
||||||
throwIfError();
|
|
||||||
tokens_.push(scalar);
|
tokens_.push(scalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,7 +653,6 @@ struct Scanner
|
||||||
// change this flag if the scan is finished at the beginning of the line.
|
// change this flag if the scan is finished at the beginning of the line.
|
||||||
allowSimpleKey_ = false;
|
allowSimpleKey_ = false;
|
||||||
auto plain = scanPlain();
|
auto plain = scanPlain();
|
||||||
throwIfError();
|
|
||||||
|
|
||||||
// Scan and add SCALAR. May change allowSimpleKey_
|
// Scan and add SCALAR. May change allowSimpleKey_
|
||||||
tokens_.push(plain);
|
tokens_.push(plain);
|
||||||
|
@ -802,21 +743,14 @@ struct Scanner
|
||||||
///
|
///
|
||||||
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
void scanAlphaNumericToSlice(string name)(const Mark startMark)
|
void scanAlphaNumericToSlice(string name)(const Mark startMark)
|
||||||
{
|
{
|
||||||
size_t length;
|
size_t length;
|
||||||
dchar c = reader_.peek();
|
dchar c = reader_.peek();
|
||||||
while(c.isAlphaNum || c.among!('-', '_')) { c = reader_.peek(++length); }
|
while(c.isAlphaNum || c.among!('-', '_')) { c = reader_.peek(++length); }
|
||||||
|
|
||||||
if(length == 0)
|
enforce(length > 0, new ScannerException("While scanning " ~ name,
|
||||||
{
|
startMark, expected("alphanumeric, '-' or '_'", c), reader_.mark));
|
||||||
enum contextMsg = "While scanning " ~ name;
|
|
||||||
error(contextMsg, startMark, expected("alphanumeric, '-' or '_'", c),
|
|
||||||
reader_.mark);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
reader_.sliceBuilder.write(reader_.get(length));
|
reader_.sliceBuilder.write(reader_.get(length));
|
||||||
}
|
}
|
||||||
|
@ -890,7 +824,6 @@ struct Scanner
|
||||||
// Scan directive name
|
// Scan directive name
|
||||||
reader_.sliceBuilder.begin();
|
reader_.sliceBuilder.begin();
|
||||||
scanDirectiveNameToSlice(startMark);
|
scanDirectiveNameToSlice(startMark);
|
||||||
if(error_) { return Token.init; }
|
|
||||||
const name = reader_.sliceBuilder.finish();
|
const name = reader_.sliceBuilder.finish();
|
||||||
|
|
||||||
reader_.sliceBuilder.begin();
|
reader_.sliceBuilder.begin();
|
||||||
|
@ -899,7 +832,6 @@ struct Scanner
|
||||||
uint tagHandleEnd = uint.max;
|
uint tagHandleEnd = uint.max;
|
||||||
if(name == "YAML") { scanYAMLDirectiveValueToSlice(startMark); }
|
if(name == "YAML") { scanYAMLDirectiveValueToSlice(startMark); }
|
||||||
else if(name == "TAG") { tagHandleEnd = scanTagDirectiveValueToSlice(startMark); }
|
else if(name == "TAG") { tagHandleEnd = scanTagDirectiveValueToSlice(startMark); }
|
||||||
if(error_) { return Token.init; }
|
|
||||||
char[] value = reader_.sliceBuilder.finish();
|
char[] value = reader_.sliceBuilder.finish();
|
||||||
|
|
||||||
Mark endMark = reader_.mark;
|
Mark endMark = reader_.mark;
|
||||||
|
@ -914,7 +846,6 @@ struct Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
scanDirectiveIgnoredLine(startMark);
|
scanDirectiveIgnoredLine(startMark);
|
||||||
if(error_) { return Token.init; }
|
|
||||||
|
|
||||||
return directiveToken(startMark, endMark, value, directive, tagHandleEnd);
|
return directiveToken(startMark, endMark, value, directive, tagHandleEnd);
|
||||||
}
|
}
|
||||||
|
@ -923,66 +854,49 @@ struct Scanner
|
||||||
///
|
///
|
||||||
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
void scanDirectiveNameToSlice(const Mark startMark) @safe
|
void scanDirectiveNameToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
// Scan directive name.
|
// Scan directive name.
|
||||||
scanAlphaNumericToSlice!"a directive"(startMark);
|
scanAlphaNumericToSlice!"a directive"(startMark);
|
||||||
if(error_) { return; }
|
|
||||||
|
|
||||||
if(reader_.peek().among!(' ', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029')) { return; }
|
enforce(reader_.peek().among!(' ', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029'),
|
||||||
error("While scanning a directive", startMark,
|
new ScannerException("While scanning a directive", startMark,
|
||||||
expected("alphanumeric, '-' or '_'", reader_.peek()), reader_.mark);
|
expected("alphanumeric, '-' or '_'", reader_.peek()), reader_.mark));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scan value of a YAML directive token. Returns major, minor version separated by '.'.
|
/// Scan value of a YAML directive token. Returns major, minor version separated by '.'.
|
||||||
///
|
///
|
||||||
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
void scanYAMLDirectiveValueToSlice(const Mark startMark) @safe
|
void scanYAMLDirectiveValueToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
findNextNonSpace();
|
findNextNonSpace();
|
||||||
|
|
||||||
scanYAMLDirectiveNumberToSlice(startMark);
|
scanYAMLDirectiveNumberToSlice(startMark);
|
||||||
if(error_) { return; }
|
|
||||||
|
|
||||||
if(reader_.peekByte() != '.')
|
enforce(reader_.peekByte() == '.',
|
||||||
{
|
new ScannerException("While scanning a directive", startMark,
|
||||||
error("While scanning a directive", startMark,
|
expected("digit or '.'", reader_.peek()), reader_.mark));
|
||||||
expected("digit or '.'", reader_.peek()), reader_.mark);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Skip the '.'.
|
// Skip the '.'.
|
||||||
reader_.forward();
|
reader_.forward();
|
||||||
|
|
||||||
reader_.sliceBuilder.write('.');
|
reader_.sliceBuilder.write('.');
|
||||||
scanYAMLDirectiveNumberToSlice(startMark);
|
scanYAMLDirectiveNumberToSlice(startMark);
|
||||||
if(error_) { return; }
|
|
||||||
|
|
||||||
if(!reader_.peek().among!(' ', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029'))
|
enforce(reader_.peek().among!(' ', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029'),
|
||||||
{
|
new ScannerException("While scanning a directive", startMark,
|
||||||
error("While scanning a directive", startMark,
|
expected("digit or '.'", reader_.peek()), reader_.mark));
|
||||||
expected("digit or '.'", reader_.peek()), reader_.mark);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scan a number from a YAML directive.
|
/// Scan a number from a YAML directive.
|
||||||
///
|
///
|
||||||
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
void scanYAMLDirectiveNumberToSlice(const Mark startMark) @safe
|
void scanYAMLDirectiveNumberToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
if(!isDigit(reader_.peek()))
|
enforce(isDigit(reader_.peek()),
|
||||||
{
|
new ScannerException("While scanning a directive", startMark,
|
||||||
error("While scanning a directive", startMark,
|
expected("digit", reader_.peek()), reader_.mark));
|
||||||
expected("digit", reader_.peek()), reader_.mark);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Already found the first digit in the enforce(), so set length to 1.
|
// Already found the first digit in the enforce(), so set length to 1.
|
||||||
uint length = 1;
|
uint length = 1;
|
||||||
|
@ -997,14 +911,11 @@ struct Scanner
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
///
|
||||||
/// Returns: Length of tag handle (which is before tag prefix) in scanned data
|
/// Returns: Length of tag handle (which is before tag prefix) in scanned data
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
uint scanTagDirectiveValueToSlice(const Mark startMark) @safe
|
uint scanTagDirectiveValueToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
findNextNonSpace();
|
findNextNonSpace();
|
||||||
const startLength = reader_.sliceBuilder.length;
|
const startLength = reader_.sliceBuilder.length;
|
||||||
scanTagDirectiveHandleToSlice(startMark);
|
scanTagDirectiveHandleToSlice(startMark);
|
||||||
if(error_) { return uint.max; }
|
|
||||||
const handleLength = cast(uint)(reader_.sliceBuilder.length - startLength);
|
const handleLength = cast(uint)(reader_.sliceBuilder.length - startLength);
|
||||||
findNextNonSpace();
|
findNextNonSpace();
|
||||||
scanTagDirectivePrefixToSlice(startMark);
|
scanTagDirectivePrefixToSlice(startMark);
|
||||||
|
@ -1016,45 +927,35 @@ struct Scanner
|
||||||
///
|
///
|
||||||
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
void scanTagDirectiveHandleToSlice(const Mark startMark) @safe
|
void scanTagDirectiveHandleToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
scanTagHandleToSlice!"directive"(startMark);
|
scanTagHandleToSlice!"directive"(startMark);
|
||||||
if(error_) { return; }
|
enforce(reader_.peekByte() == ' ',
|
||||||
if(reader_.peekByte() == ' ') { return; }
|
new ScannerException("While scanning a directive handle", startMark,
|
||||||
error("While scanning a directive handle", startMark,
|
expected("' '", reader_.peek()), reader_.mark));
|
||||||
expected("' '", reader_.peek()), reader_.mark);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scan prefix of a tag directive.
|
/// Scan prefix of a tag directive.
|
||||||
///
|
///
|
||||||
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
void scanTagDirectivePrefixToSlice(const Mark startMark) @safe
|
void scanTagDirectivePrefixToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
scanTagURIToSlice!"directive"(startMark);
|
scanTagURIToSlice!"directive"(startMark);
|
||||||
if(reader_.peek().among!(' ', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029')) { return; }
|
enforce(reader_.peek().among!(' ', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029'),
|
||||||
error("While scanning a directive prefix", startMark,
|
new ScannerException("While scanning a directive prefix", startMark,
|
||||||
expected("' '", reader_.peek()), reader_.mark);
|
expected("' '", reader_.peek()), reader_.mark));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scan (and ignore) ignored line after a directive.
|
/// Scan (and ignore) ignored line after a directive.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
void scanDirectiveIgnoredLine(const Mark startMark) @safe
|
void scanDirectiveIgnoredLine(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
findNextNonSpace();
|
findNextNonSpace();
|
||||||
if(reader_.peekByte() == '#') { scanToNextBreak(); }
|
if(reader_.peekByte() == '#') { scanToNextBreak(); }
|
||||||
if(reader_.peek().isBreak)
|
enforce(reader_.peek().isBreak,
|
||||||
{
|
new ScannerException("While scanning a directive", startMark,
|
||||||
scanLineBreak();
|
expected("comment or a line break", reader_.peek()), reader_.mark));
|
||||||
return;
|
scanLineBreak();
|
||||||
}
|
|
||||||
error("While scanning a directive", startMark,
|
|
||||||
expected("comment or a line break", reader_.peek()), reader_.mark);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1068,8 +969,6 @@ struct Scanner
|
||||||
/// and
|
/// and
|
||||||
/// [ *alias , "value" ]
|
/// [ *alias , "value" ]
|
||||||
/// Therefore we restrict aliases to ASCII alphanumeric characters.
|
/// Therefore we restrict aliases to ASCII alphanumeric characters.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
Token scanAnchor(const TokenID id) @safe
|
Token scanAnchor(const TokenID id) @safe
|
||||||
{
|
{
|
||||||
const startMark = reader_.mark;
|
const startMark = reader_.mark;
|
||||||
|
@ -1080,17 +979,13 @@ struct Scanner
|
||||||
else { scanAlphaNumericToSlice!"an anchor"(startMark); }
|
else { scanAlphaNumericToSlice!"an anchor"(startMark); }
|
||||||
// On error, value is discarded as we return immediately
|
// On error, value is discarded as we return immediately
|
||||||
char[] value = reader_.sliceBuilder.finish();
|
char[] value = reader_.sliceBuilder.finish();
|
||||||
if(error_) { return Token.init; }
|
|
||||||
|
|
||||||
if(!reader_.peek().isWhiteSpace &&
|
enum anchorCtx = "While scanning an anchor";
|
||||||
!reader_.peekByte().among!('?', ':', ',', ']', '}', '%', '@'))
|
enum aliasCtx = "While scanning an alias";
|
||||||
{
|
enforce(reader_.peek().isWhiteSpace ||
|
||||||
enum anchorCtx = "While scanning an anchor";
|
reader_.peekByte().among!('?', ':', ',', ']', '}', '%', '@'),
|
||||||
enum aliasCtx = "While scanning an alias";
|
new ScannerException(i == '*' ? aliasCtx : anchorCtx, startMark,
|
||||||
error(i == '*' ? aliasCtx : anchorCtx, startMark,
|
expected("alphanumeric, '-' or '_'", reader_.peek()), reader_.mark));
|
||||||
expected("alphanumeric, '-' or '_'", reader_.peek()), reader_.mark);
|
|
||||||
return Token.init;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(id == TokenID.alias_)
|
if(id == TokenID.alias_)
|
||||||
{
|
{
|
||||||
|
@ -1104,8 +999,6 @@ struct Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scan a tag token.
|
/// Scan a tag token.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
Token scanTag() @safe
|
Token scanTag() @safe
|
||||||
{
|
{
|
||||||
const startMark = reader_.mark;
|
const startMark = reader_.mark;
|
||||||
|
@ -1123,13 +1016,9 @@ struct Scanner
|
||||||
|
|
||||||
handleEnd = 0;
|
handleEnd = 0;
|
||||||
scanTagURIToSlice!"tag"(startMark);
|
scanTagURIToSlice!"tag"(startMark);
|
||||||
if(error_) { return Token.init; }
|
enforce(reader_.peekByte() == '>',
|
||||||
if(reader_.peekByte() != '>')
|
new ScannerException("While scanning a tag", startMark,
|
||||||
{
|
expected("'>'", reader_.peek()), reader_.mark));
|
||||||
error("While scanning a tag", startMark,
|
|
||||||
expected("'>'", reader_.peek()), reader_.mark);
|
|
||||||
return Token.init;
|
|
||||||
}
|
|
||||||
reader_.forward();
|
reader_.forward();
|
||||||
}
|
}
|
||||||
else if(c.isWhiteSpace)
|
else if(c.isWhiteSpace)
|
||||||
|
@ -1158,7 +1047,6 @@ struct Scanner
|
||||||
{
|
{
|
||||||
scanTagHandleToSlice!"tag"(startMark);
|
scanTagHandleToSlice!"tag"(startMark);
|
||||||
handleEnd = cast(uint)reader_.sliceBuilder.length;
|
handleEnd = cast(uint)reader_.sliceBuilder.length;
|
||||||
if(error_) { return Token.init; }
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1168,23 +1056,17 @@ struct Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
scanTagURIToSlice!"tag"(startMark);
|
scanTagURIToSlice!"tag"(startMark);
|
||||||
if(error_) { return Token.init; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(reader_.peek().isBreakOrSpace)
|
enforce(reader_.peek().isBreakOrSpace,
|
||||||
{
|
new ScannerException("While scanning a tag", startMark, expected("' '", reader_.peek()),
|
||||||
char[] slice = reader_.sliceBuilder.finish();
|
reader_.mark));
|
||||||
return tagToken(startMark, reader_.mark, slice, handleEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
error("While scanning a tag", startMark, expected("' '", reader_.peek()),
|
char[] slice = reader_.sliceBuilder.finish();
|
||||||
reader_.mark);
|
return tagToken(startMark, reader_.mark, slice, handleEnd);
|
||||||
return Token.init;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scan a block scalar token with specified style.
|
/// Scan a block scalar token with specified style.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
Token scanBlockScalar(const ScalarStyle style) @safe
|
Token scanBlockScalar(const ScalarStyle style) @safe
|
||||||
{
|
{
|
||||||
const startMark = reader_.mark;
|
const startMark = reader_.mark;
|
||||||
|
@ -1193,12 +1075,10 @@ struct Scanner
|
||||||
reader_.forward();
|
reader_.forward();
|
||||||
|
|
||||||
const indicators = scanBlockScalarIndicators(startMark);
|
const indicators = scanBlockScalarIndicators(startMark);
|
||||||
if(error_) { return Token.init; }
|
|
||||||
|
|
||||||
const chomping = indicators[0];
|
const chomping = indicators[0];
|
||||||
const increment = indicators[1];
|
const increment = indicators[1];
|
||||||
scanBlockScalarIgnoredLine(startMark);
|
scanBlockScalarIgnoredLine(startMark);
|
||||||
if(error_) { return Token.init; }
|
|
||||||
|
|
||||||
// Determine the indentation level and go to the first non-empty line.
|
// Determine the indentation level and go to the first non-empty line.
|
||||||
Mark endMark;
|
Mark endMark;
|
||||||
|
@ -1325,8 +1205,6 @@ struct Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scan chomping and indentation indicators of a scalar token.
|
/// Scan chomping and indentation indicators of a scalar token.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
Tuple!(Chomping, int) scanBlockScalarIndicators(const Mark startMark) @safe
|
Tuple!(Chomping, int) scanBlockScalarIndicators(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
auto chomping = Chomping.clip;
|
auto chomping = Chomping.clip;
|
||||||
|
@ -1337,22 +1215,18 @@ struct Scanner
|
||||||
if(getChomping(c, chomping))
|
if(getChomping(c, chomping))
|
||||||
{
|
{
|
||||||
getIncrement(c, increment, startMark);
|
getIncrement(c, increment, startMark);
|
||||||
if(error_) { return tuple(Chomping.init, int.max); }
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const gotIncrement = getIncrement(c, increment, startMark);
|
const gotIncrement = getIncrement(c, increment, startMark);
|
||||||
if(error_) { return tuple(Chomping.init, int.max); }
|
|
||||||
if(gotIncrement) { getChomping(c, chomping); }
|
if(gotIncrement) { getChomping(c, chomping); }
|
||||||
}
|
}
|
||||||
|
|
||||||
if(c.among!(' ', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029'))
|
enforce(c.among!(' ', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029'),
|
||||||
{
|
new ScannerException("While scanning a block scalar", startMark,
|
||||||
return tuple(chomping, increment);
|
expected("chomping or indentation indicator", c), reader_.mark));
|
||||||
}
|
|
||||||
error("While scanning a block scalar", startMark,
|
return tuple(chomping, increment);
|
||||||
expected("chomping or indentation indicator", c), reader_.mark);
|
|
||||||
return tuple(Chomping.init, int.max);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get chomping indicator, if detected. Return false otherwise.
|
/// Get chomping indicator, if detected. Return false otherwise.
|
||||||
|
@ -1383,40 +1257,33 @@ struct Scanner
|
||||||
/// the next character in the Reader.
|
/// the next character in the Reader.
|
||||||
/// increment = Write the increment value here, if detected.
|
/// increment = Write the increment value here, if detected.
|
||||||
/// startMark = Mark for error messages.
|
/// startMark = Mark for error messages.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
bool getIncrement(ref dchar c, ref int increment, const Mark startMark) @safe
|
bool getIncrement(ref dchar c, ref int increment, const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
if(!c.isDigit) { return false; }
|
if(!c.isDigit) { return false; }
|
||||||
// Convert a digit to integer.
|
// Convert a digit to integer.
|
||||||
increment = c - '0';
|
increment = c - '0';
|
||||||
assert(increment < 10 && increment >= 0, "Digit has invalid value");
|
assert(increment < 10 && increment >= 0, "Digit has invalid value");
|
||||||
if(increment > 0)
|
|
||||||
{
|
enforce(increment > 0,
|
||||||
reader_.forward();
|
new ScannerException("While scanning a block scalar", startMark,
|
||||||
c = reader_.peek();
|
expected("indentation indicator in range 1-9", "0"), reader_.mark));
|
||||||
return true;
|
|
||||||
}
|
reader_.forward();
|
||||||
error("While scanning a block scalar", startMark,
|
c = reader_.peek();
|
||||||
expected("indentation indicator in range 1-9", "0"), reader_.mark);
|
return true;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scan (and ignore) ignored line in a block scalar.
|
/// Scan (and ignore) ignored line in a block scalar.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
void scanBlockScalarIgnoredLine(const Mark startMark) @safe
|
void scanBlockScalarIgnoredLine(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
findNextNonSpace();
|
findNextNonSpace();
|
||||||
if(reader_.peekByte()== '#') { scanToNextBreak(); }
|
if(reader_.peekByte()== '#') { scanToNextBreak(); }
|
||||||
|
|
||||||
if(reader_.peek().isBreak)
|
enforce(reader_.peek().isBreak,
|
||||||
{
|
new ScannerException("While scanning a block scalar", startMark,
|
||||||
scanLineBreak();
|
expected("comment or line break", reader_.peek()), reader_.mark));
|
||||||
return;
|
|
||||||
}
|
scanLineBreak();
|
||||||
error("While scanning a block scalar", startMark,
|
|
||||||
expected("comment or line break", reader_.peek()), reader_.mark);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scan indentation in a block scalar, returning line breaks, max indent and end mark.
|
/// Scan indentation in a block scalar, returning line breaks, max indent and end mark.
|
||||||
|
@ -1463,25 +1330,19 @@ struct Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scan a qouted flow scalar token with specified quotes.
|
/// Scan a qouted flow scalar token with specified quotes.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
Token scanFlowScalar(const ScalarStyle quotes) @safe
|
Token scanFlowScalar(const ScalarStyle quotes) @safe
|
||||||
{
|
{
|
||||||
const startMark = reader_.mark;
|
const startMark = reader_.mark;
|
||||||
const quote = reader_.get();
|
const quote = reader_.get();
|
||||||
|
|
||||||
reader_.sliceBuilder.begin();
|
reader_.sliceBuilder.begin();
|
||||||
scope(exit) if(error_) { reader_.sliceBuilder.finish(); }
|
|
||||||
|
|
||||||
scanFlowScalarNonSpacesToSlice(quotes, startMark);
|
scanFlowScalarNonSpacesToSlice(quotes, startMark);
|
||||||
if(error_) { return Token.init; }
|
|
||||||
|
|
||||||
while(reader_.peek() != quote)
|
while(reader_.peek() != quote)
|
||||||
{
|
{
|
||||||
scanFlowScalarSpacesToSlice(startMark);
|
scanFlowScalarSpacesToSlice(startMark);
|
||||||
if(error_) { return Token.init; }
|
|
||||||
scanFlowScalarNonSpacesToSlice(quotes, startMark);
|
scanFlowScalarNonSpacesToSlice(quotes, startMark);
|
||||||
if(error_) { return Token.init; }
|
|
||||||
}
|
}
|
||||||
reader_.forward();
|
reader_.forward();
|
||||||
|
|
||||||
|
@ -1493,8 +1354,6 @@ struct Scanner
|
||||||
///
|
///
|
||||||
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
void scanFlowScalarNonSpacesToSlice(const ScalarStyle quotes, const Mark startMark)
|
void scanFlowScalarNonSpacesToSlice(const ScalarStyle quotes, const Mark startMark)
|
||||||
@safe
|
@safe
|
||||||
{
|
{
|
||||||
|
@ -1510,12 +1369,10 @@ struct Scanner
|
||||||
// This will not necessarily make slice 32 chars longer, as not all
|
// This will not necessarily make slice 32 chars longer, as not all
|
||||||
// code points are 1 char.
|
// code points are 1 char.
|
||||||
const char[] slice = reader_.slice(numCodePoints + 32);
|
const char[] slice = reader_.slice(numCodePoints + 32);
|
||||||
if(slice.length == oldSliceLength)
|
enforce(slice.length != oldSliceLength,
|
||||||
{
|
new ScannerException("While reading a flow scalar", startMark,
|
||||||
error("While reading a flow scalar", startMark,
|
"reached end of file", reader_.mark));
|
||||||
"reached end of file", reader_.mark);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for(size_t i = oldSliceLength; i < slice.length;)
|
for(size_t i = oldSliceLength; i < slice.length;)
|
||||||
{
|
{
|
||||||
// slice is UTF-8 - need to decode
|
// slice is UTF-8 - need to decode
|
||||||
|
@ -1558,45 +1415,34 @@ struct Scanner
|
||||||
const hexLength = dyaml.escapes.escapeHexLength(c);
|
const hexLength = dyaml.escapes.escapeHexLength(c);
|
||||||
reader_.forward();
|
reader_.forward();
|
||||||
|
|
||||||
foreach(i; 0 .. hexLength) if(!reader_.peek(i).isHexDigit)
|
foreach(i; 0 .. hexLength) {
|
||||||
{
|
enforce(reader_.peek(i).isHexDigit,
|
||||||
error("While scanning a double quoted scalar", startMark,
|
new ScannerException("While scanning a double quoted scalar", startMark,
|
||||||
expected("escape sequence of hexadecimal numbers",
|
expected("escape sequence of hexadecimal numbers",
|
||||||
reader_.peek(i)), reader_.mark);
|
reader_.peek(i)), reader_.mark));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
char[] hex = reader_.get(hexLength);
|
char[] hex = reader_.get(hexLength);
|
||||||
|
|
||||||
|
enforce((hex.length > 0) && (hex.length <= 8),
|
||||||
|
new ScannerException("While scanning a double quoted scalar", startMark,
|
||||||
|
"overflow when parsing an escape sequence of " ~
|
||||||
|
"hexadecimal numbers.", reader_.mark));
|
||||||
|
|
||||||
char[2] escapeStart = ['\\', cast(char) c];
|
char[2] escapeStart = ['\\', cast(char) c];
|
||||||
reader_.sliceBuilder.write(escapeStart);
|
reader_.sliceBuilder.write(escapeStart);
|
||||||
reader_.sliceBuilder.write(hex);
|
reader_.sliceBuilder.write(hex);
|
||||||
// Note: This is just error checking; Parser does the actual
|
|
||||||
// escaping (otherwise we could accidentally create an
|
|
||||||
// escape sequence here that wasn't in input, breaking the
|
|
||||||
// escaping code in parser, which is in parser because it
|
|
||||||
// can't always be done in place)
|
|
||||||
try {
|
|
||||||
parse!int(hex, 16u);
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
error("While scanning a double quoted scalar", startMark,
|
|
||||||
"overflow when parsing an escape sequence of " ~
|
|
||||||
"hexadecimal numbers.", reader_.mark);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(c.among!('\n', '\r', '\u0085', '\u2028', '\u2029'))
|
else if(c.among!('\n', '\r', '\u0085', '\u2028', '\u2029'))
|
||||||
{
|
{
|
||||||
scanLineBreak();
|
scanLineBreak();
|
||||||
scanFlowScalarBreaksToSlice(startMark);
|
scanFlowScalarBreaksToSlice(startMark);
|
||||||
if(error_) { return; }
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error("While scanning a double quoted scalar", startMark,
|
throw new ScannerException("While scanning a double quoted scalar", startMark,
|
||||||
buildMsg("found unsupported escape character", c),
|
text("found unsupported escape character ", c),
|
||||||
reader_.mark);
|
reader_.mark);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { return; }
|
else { return; }
|
||||||
|
@ -1607,8 +1453,6 @@ struct Scanner
|
||||||
///
|
///
|
||||||
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
||||||
/// spaces into that slice.
|
/// spaces into that slice.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
void scanFlowScalarSpacesToSlice(const Mark startMark) @safe
|
void scanFlowScalarSpacesToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
// Increase length as long as we see whitespace.
|
// Increase length as long as we see whitespace.
|
||||||
|
@ -1618,12 +1462,9 @@ struct Scanner
|
||||||
|
|
||||||
// Can check the last byte without striding because '\0' is ASCII
|
// Can check the last byte without striding because '\0' is ASCII
|
||||||
const c = reader_.peek(length);
|
const c = reader_.peek(length);
|
||||||
if(c == '\0')
|
enforce(c != '\0',
|
||||||
{
|
new ScannerException("While scanning a quoted scalar", startMark,
|
||||||
error("While scanning a quoted scalar", startMark,
|
"found unexpected end of buffer", reader_.mark));
|
||||||
"found unexpected end of buffer", reader_.mark);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spaces not followed by a line break.
|
// Spaces not followed by a line break.
|
||||||
if(!c.among!('\n', '\r', '\u0085', '\u2028', '\u2029'))
|
if(!c.among!('\n', '\r', '\u0085', '\u2028', '\u2029'))
|
||||||
|
@ -1642,7 +1483,6 @@ struct Scanner
|
||||||
// If we have extra line breaks after the first, scan them into the
|
// If we have extra line breaks after the first, scan them into the
|
||||||
// slice.
|
// slice.
|
||||||
const bool extraBreaks = scanFlowScalarBreaksToSlice(startMark);
|
const bool extraBreaks = scanFlowScalarBreaksToSlice(startMark);
|
||||||
if(error_) { return; }
|
|
||||||
|
|
||||||
// No extra breaks, one normal line break. Replace it with a space.
|
// No extra breaks, one normal line break. Replace it with a space.
|
||||||
if(lineBreak == '\n' && !extraBreaks) { reader_.sliceBuilder.write(' '); }
|
if(lineBreak == '\n' && !extraBreaks) { reader_.sliceBuilder.write(' '); }
|
||||||
|
@ -1652,8 +1492,6 @@ struct Scanner
|
||||||
///
|
///
|
||||||
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
||||||
/// line breaks into that slice.
|
/// line breaks into that slice.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
bool scanFlowScalarBreaksToSlice(const Mark startMark) @safe
|
bool scanFlowScalarBreaksToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
// True if at least one line break was found.
|
// True if at least one line break was found.
|
||||||
|
@ -1662,13 +1500,10 @@ struct Scanner
|
||||||
{
|
{
|
||||||
// Instead of checking indentation, we check for document separators.
|
// Instead of checking indentation, we check for document separators.
|
||||||
const prefix = reader_.prefix(3);
|
const prefix = reader_.prefix(3);
|
||||||
if((prefix == "---" || prefix == "...") &&
|
enforce(!(prefix == "---" || prefix == "...") ||
|
||||||
reader_.peek(3).isWhiteSpace)
|
!reader_.peek(3).isWhiteSpace,
|
||||||
{
|
new ScannerException("While scanning a quoted scalar", startMark,
|
||||||
error("While scanning a quoted scalar", startMark,
|
"found unexpected document separator", reader_.mark));
|
||||||
"found unexpected document separator", reader_.mark);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip any whitespaces.
|
// Skip any whitespaces.
|
||||||
while(reader_.peekByte().among!(' ', '\t')) { reader_.forward(); }
|
while(reader_.peekByte().among!(' ', '\t')) { reader_.forward(); }
|
||||||
|
@ -1684,8 +1519,6 @@ struct Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scan plain scalar token (no block, no quotes).
|
/// Scan plain scalar token (no block, no quotes).
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
Token scanPlain() @safe
|
Token scanPlain() @safe
|
||||||
{
|
{
|
||||||
// We keep track of the allowSimpleKey_ flag here.
|
// We keep track of the allowSimpleKey_ flag here.
|
||||||
|
@ -1738,20 +1571,13 @@ struct Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's not clear what we should do with ':' in the flow context.
|
// It's not clear what we should do with ':' in the flow context.
|
||||||
if(flowLevel_ > 0 && c == ':' &&
|
enforce(flowLevel_ == 0 || c != ':' ||
|
||||||
!reader_.peek(length + 1).isWhiteSpace &&
|
reader_.peek(length + 1).isWhiteSpace ||
|
||||||
!reader_.peek(length + 1).among!(',', '[', ']', '{', '}'))
|
reader_.peek(length + 1).among!(',', '[', ']', '{', '}'),
|
||||||
{
|
new ScannerException("While scanning a plain scalar", startMark,
|
||||||
// This is an error; throw the slice away.
|
"found unexpected ':' . Please check " ~
|
||||||
spacesTransaction.commit();
|
"http://pyyaml.org/wiki/YAMLColonInFlowContext for details.",
|
||||||
reader_.sliceBuilder.finish();
|
reader_.mark));
|
||||||
reader_.forward(length);
|
|
||||||
error("While scanning a plain scalar", startMark,
|
|
||||||
"found unexpected ':' . Please check " ~
|
|
||||||
"http://pyyaml.org/wiki/YAMLColonInFlowContext for details.",
|
|
||||||
reader_.mark);
|
|
||||||
return Token.init;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(length == 0) { break; }
|
if(length == 0) { break; }
|
||||||
|
|
||||||
|
@ -1842,17 +1668,12 @@ struct Scanner
|
||||||
///
|
///
|
||||||
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
void scanTagHandleToSlice(string name)(const Mark startMark)
|
void scanTagHandleToSlice(string name)(const Mark startMark)
|
||||||
{
|
{
|
||||||
dchar c = reader_.peek();
|
dchar c = reader_.peek();
|
||||||
enum contextMsg = "While scanning a " ~ name;
|
enum contextMsg = "While scanning a " ~ name;
|
||||||
if(c != '!')
|
enforce(c == '!',
|
||||||
{
|
new ScannerException(contextMsg, startMark, expected("'!'", c), reader_.mark));
|
||||||
error(contextMsg, startMark, expected("'!'", c), reader_.mark);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint length = 1;
|
uint length = 1;
|
||||||
c = reader_.peek(length);
|
c = reader_.peek(length);
|
||||||
|
@ -1863,12 +1684,8 @@ struct Scanner
|
||||||
++length;
|
++length;
|
||||||
c = reader_.peek(length);
|
c = reader_.peek(length);
|
||||||
}
|
}
|
||||||
if(c != '!')
|
enforce(c == '!',
|
||||||
{
|
new ScannerException(contextMsg, startMark, expected("'!'", c), reader_.mark));
|
||||||
reader_.forward(length);
|
|
||||||
error(contextMsg, startMark, expected("'!'", c), reader_.mark);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
++length;
|
++length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1879,8 +1696,6 @@ struct Scanner
|
||||||
///
|
///
|
||||||
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
void scanTagURIToSlice(string name)(const Mark startMark)
|
void scanTagURIToSlice(string name)(const Mark startMark)
|
||||||
{
|
{
|
||||||
// Note: we do not check if URI is well-formed.
|
// Note: we do not check if URI is well-formed.
|
||||||
|
@ -1896,7 +1711,6 @@ struct Scanner
|
||||||
reader_.sliceBuilder.write(chars);
|
reader_.sliceBuilder.write(chars);
|
||||||
length = 0;
|
length = 0;
|
||||||
scanURIEscapesToSlice!name(startMark);
|
scanURIEscapesToSlice!name(startMark);
|
||||||
if(error_) { return; }
|
|
||||||
}
|
}
|
||||||
else { ++length; }
|
else { ++length; }
|
||||||
c = reader_.peek(length);
|
c = reader_.peek(length);
|
||||||
|
@ -1909,10 +1723,9 @@ struct Scanner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// OK if we scanned something, error otherwise.
|
// OK if we scanned something, error otherwise.
|
||||||
if(reader_.sliceBuilder.length > startLen) { return; }
|
|
||||||
|
|
||||||
enum contextMsg = "While parsing a " ~ name;
|
enum contextMsg = "While parsing a " ~ name;
|
||||||
error(contextMsg, startMark, expected("URI", c), reader_.mark);
|
enforce(reader_.sliceBuilder.length > startLen,
|
||||||
|
new ScannerException(contextMsg, startMark, expected("URI", c), reader_.mark));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not @nogc yet because std.utf.decode is not @nogc
|
// Not @nogc yet because std.utf.decode is not @nogc
|
||||||
|
@ -1920,8 +1733,6 @@ struct Scanner
|
||||||
///
|
///
|
||||||
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
/// Assumes that the caller is building a slice in Reader, and puts the scanned
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
|
||||||
void scanURIEscapesToSlice(string name)(const Mark startMark)
|
void scanURIEscapesToSlice(string name)(const Mark startMark)
|
||||||
{
|
{
|
||||||
import core.exception : UnicodeException;
|
import core.exception : UnicodeException;
|
||||||
|
@ -1935,13 +1746,12 @@ struct Scanner
|
||||||
{
|
{
|
||||||
reader_.forward();
|
reader_.forward();
|
||||||
char[2] nextByte = [reader_.peekByte(), reader_.peekByte(1)];
|
char[2] nextByte = [reader_.peekByte(), reader_.peekByte(1)];
|
||||||
if(!nextByte[0].isHexDigit || !nextByte[1].isHexDigit)
|
|
||||||
{
|
enforce(nextByte[0].isHexDigit && nextByte[1].isHexDigit,
|
||||||
auto msg = expected("URI escape sequence of 2 hexadecimal " ~
|
new ScannerException(contextMsg, startMark,
|
||||||
"numbers", nextByte);
|
expected("URI escape sequence of 2 hexadecimal " ~
|
||||||
error(contextMsg, startMark, msg, reader_.mark);
|
"numbers", nextByte), reader_.mark));
|
||||||
return;
|
|
||||||
}
|
|
||||||
buffer ~= nextByte[].to!ubyte(16);
|
buffer ~= nextByte[].to!ubyte(16);
|
||||||
|
|
||||||
reader_.forward(2);
|
reader_.forward(2);
|
||||||
|
@ -1955,10 +1765,9 @@ struct Scanner
|
||||||
}
|
}
|
||||||
catch (UnicodeException)
|
catch (UnicodeException)
|
||||||
{
|
{
|
||||||
error(contextMsg, startMark,
|
throw new ScannerException(contextMsg, startMark,
|
||||||
"Invalid UTF-8 data encoded in URI escape sequence",
|
"Invalid UTF-8 data encoded in URI escape sequence",
|
||||||
reader_.mark);
|
reader_.mark);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue