diff --git a/source/dyaml/exception.d b/source/dyaml/exception.d index 7e05b96..2f13a44 100644 --- a/source/dyaml/exception.d +++ b/source/dyaml/exception.d @@ -29,6 +29,8 @@ class YAMLException : Exception struct Mark { package: + /// File name. + string name_; /// Line number. ushort line_; /// Column number. @@ -36,14 +38,21 @@ struct Mark public: /// Construct a Mark with specified line and column in the file. - this(const uint line, const uint column) @safe pure nothrow @nogc + this(string name, const uint line, const uint column) @safe pure nothrow @nogc { + name_ = name; line_ = cast(ushort)min(ushort.max, line); // This *will* overflow on extremely wide files but saves CPU time // (mark ctor takes ~5% of time) column_ = cast(ushort)column; } + /// Get a file name. + @property string name() @safe pure nothrow @nogc const + { + return name_; + } + /// Get a line number. @property ushort line() @safe pure nothrow @nogc const { @@ -64,7 +73,7 @@ struct Mark { return text(v + 1, v == ushort.max ? " or higher" : ""); } - return "line " ~ clamped(line_) ~ ",column " ~ clamped(column_); + return "file " ~ name_ ~ ",line " ~ clamped(line_) ~ ",column " ~ clamped(column_); } } diff --git a/source/dyaml/loader.d b/source/dyaml/loader.d index 780862e..7e7096c 100644 --- a/source/dyaml/loader.d +++ b/source/dyaml/loader.d @@ -64,8 +64,7 @@ struct Loader { try { - auto loader = Loader(std.file.read(filename)); - loader.name_ = filename; + auto loader = Loader(std.file.read(filename), filename); return loader; } catch(FileException e) @@ -77,8 +76,7 @@ struct Loader /// ditto static Loader fromFile(File file) @system { - auto loader = Loader(file.byChunk(4096).join); - loader.name_ = file.name; + auto loader = Loader(file.byChunk(4096).join, file.name); return loader; } @@ -140,17 +138,18 @@ struct Loader return Loader(yamlData); } /// Ditto - private this(void[] yamlData) @system + private this(void[] yamlData, string name = "") @system { - this(cast(ubyte[])yamlData); + this(cast(ubyte[])yamlData, name); } /// Ditto - private this(ubyte[] yamlData) @safe + private this(ubyte[] yamlData, string name = "") @safe { resolver_ = Resolver.withDefaultResolvers; + name_ = name; try { - auto reader_ = new Reader(yamlData); + auto reader_ = new Reader(yamlData, name); scanner_ = Scanner(reader_); parser_ = new Parser(scanner_); } diff --git a/source/dyaml/reader.d b/source/dyaml/reader.d index 331ff26..9fe42fc 100644 --- a/source/dyaml/reader.d +++ b/source/dyaml/reader.d @@ -57,6 +57,8 @@ final class Reader // Number of characters (code points) in buffer_. size_t characterCount_; + // File name + string name_; // Current line in file. uint line_; // Current column in file. @@ -89,11 +91,14 @@ final class Reader /// contents of a file or a string. $(B will) be modified by /// the Reader and other parts of D:YAML (D:YAML tries to /// reuse the buffer to minimize memory allocations) + /// name = File name if the buffer is the contents of a file or + /// `""` if the buffer is the contents of a string. /// /// Throws: ReaderException on a UTF decoding error or if there are /// nonprintable Unicode characters illegal in YAML. - this(ubyte[] buffer) @safe pure + this(ubyte[] buffer, string name = "") @safe pure { + name_ = name; auto endianResult = fixUTFByteOrder(buffer); if(endianResult.bytesStripped > 0) { @@ -395,7 +400,10 @@ final class Reader SliceBuilder sliceBuilder; /// Get a string describing current buffer position, used for error messages. - Mark mark() const pure nothrow @nogc @safe { return Mark(line_, column_); } + Mark mark() const pure nothrow @nogc @safe { return Mark(name_, line_, column_); } + + /// Get file name. + string name() const @safe pure nothrow @nogc { return name_; } /// Get current line number. uint line() const @safe pure nothrow @nogc { return line_; } diff --git a/source/dyaml/scanner.d b/source/dyaml/scanner.d index d4f8253..2009521 100644 --- a/source/dyaml/scanner.d +++ b/source/dyaml/scanner.d @@ -280,7 +280,7 @@ struct Scanner { enforce(!key.required, new ScannerException("While scanning a simple key", - Mark(key.line, key.column), + Mark(reader_.name, key.line, key.column), "could not find expected ':'", reader_.mark)); key.isNull = true; } @@ -328,7 +328,7 @@ struct Scanner const key = possibleSimpleKeys_[flowLevel_]; enforce(!key.required, new ScannerException("While scanning a simple key", - Mark(key.line, key.column), + Mark(reader_.name, key.line, key.column), "could not find expected ':'", reader_.mark)); possibleSimpleKeys_[flowLevel_].isNull = true; } @@ -540,7 +540,7 @@ struct Scanner { const key = possibleSimpleKeys_[flowLevel_]; possibleSimpleKeys_[flowLevel_].isNull = true; - Mark keyMark = Mark(key.line, key.column); + Mark keyMark = Mark(reader_.name, key.line, key.column); const idx = key.tokenIndex - tokensTaken_; assert(idx >= 0);