1 2 // Copyright Ferdinand Majerech 2011. 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 7 ///Exceptions thrown by D:YAML and _exception related code. 8 module dyaml.exception; 9 10 import std.algorithm; 11 import std.array; 12 import std.conv; 13 import std.exception; 14 import std.format; 15 import std.range; 16 import std.string; 17 import std.typecons; 18 19 20 /// Base class for all exceptions thrown by D:YAML. 21 class YAMLException : Exception 22 { 23 mixin basicExceptionCtors; 24 } 25 26 /// Position in a YAML stream, used for error messages. 27 struct Mark 28 { 29 /// File name. 30 string name = "<unknown>"; 31 /// Line number. 32 ushort line; 33 /// Column number. 34 ushort column; 35 36 public: 37 /// Construct a Mark with specified line and column in the file. 38 this(string name, const uint line, const uint column) @safe pure nothrow @nogc 39 { 40 this.name = name; 41 this.line = cast(ushort)min(ushort.max, line); 42 // This *will* overflow on extremely wide files but saves CPU time 43 // (mark ctor takes ~5% of time) 44 this.column = cast(ushort)column; 45 } 46 47 /// Get a string representation of the mark. 48 void toString(W)(ref W writer) const scope 49 { 50 // Line/column numbers start at zero internally, make them start at 1. 51 void writeClamped(ushort v) 52 { 53 writer.formattedWrite!"%s"(v + 1); 54 if (v == ushort.max) 55 { 56 put(writer, "or higher"); 57 } 58 } 59 put(writer, name); 60 put(writer, ":"); 61 writeClamped(line); 62 put(writer, ","); 63 writeClamped(column); 64 } 65 } 66 67 /// Base class of YAML exceptions with marked positions of the problem. 68 abstract class MarkedYAMLException : YAMLException 69 { 70 /// Position of the error. 71 Mark mark; 72 /// Additional position information, usually the start of a token or scalar 73 Nullable!Mark mark2; 74 /// A label for the extra information 75 string mark2Label; 76 77 // Construct a MarkedYAMLException with two marks 78 this(string context, const Mark mark, string mark2Label, const Nullable!Mark mark2, 79 string file = __FILE__, size_t line = __LINE__) @safe pure nothrow 80 { 81 super(context, file, line); 82 this.mark = mark; 83 this.mark2 = mark2; 84 this.mark2Label = mark2Label; 85 } 86 87 // Construct a MarkedYAMLException with specified problem. 88 this(string msg, const Mark mark, 89 string file = __FILE__, size_t line = __LINE__) 90 @safe pure nothrow 91 { 92 super(msg, file, line); 93 this.mark = mark; 94 } 95 96 /// Custom toString to add context without requiring allocation up-front 97 void toString(W)(ref W sink) const 98 { 99 sink.formattedWrite!"%s@%s(%s): "(typeid(this).name, file, line); 100 put(sink, msg); 101 put(sink, "\n"); 102 mark.toString(sink); 103 if (!mark2.isNull) 104 { 105 put(sink, "\n"); 106 put(sink, mark2Label); 107 put(sink, ":"); 108 mark2.get.toString(sink); 109 } 110 put(sink, "\n"); 111 put(sink, info.toString()); 112 } 113 /// Ditto 114 override void toString(scope void delegate(in char[]) sink) const 115 { 116 toString!(typeof(sink))(sink); 117 } 118 /// An override of message 119 override const(char)[] message() const @safe nothrow 120 { 121 if (mark2.isNull) 122 { 123 return assertNotThrown(text(msg, "\n", mark)); 124 } 125 else 126 { 127 return assertNotThrown(text(msg, "\n", mark, "\n", mark2Label, ": ", mark2.get)); 128 } 129 } 130 } 131 132 /// Exception thrown on composer errors. 133 class ComposerException : MarkedYAMLException 134 { 135 mixin MarkedExceptionCtors; 136 } 137 138 /// Exception thrown on constructor errors. 139 class ConstructorException : MarkedYAMLException 140 { 141 mixin MarkedExceptionCtors; 142 } 143 144 /// Exception thrown on loader errors. 145 class LoaderException : MarkedYAMLException 146 { 147 mixin MarkedExceptionCtors; 148 } 149 150 /// Exception thrown on node related errors. 151 class NodeException : MarkedYAMLException 152 { 153 mixin MarkedExceptionCtors; 154 } 155 156 /// Exception thrown on parser errors. 157 class ParserException : MarkedYAMLException 158 { 159 mixin MarkedExceptionCtors; 160 } 161 162 /// Exception thrown on Reader errors. 163 class ReaderException : MarkedYAMLException 164 { 165 mixin MarkedExceptionCtors; 166 } 167 168 /// Exception thrown on Representer errors. 169 class RepresenterException : YAMLException 170 { 171 mixin basicExceptionCtors; 172 } 173 174 /// Exception thrown on scanner errors. 175 class ScannerException : MarkedYAMLException 176 { 177 mixin MarkedExceptionCtors; 178 } 179 180 private: 181 182 /// Constructors of marked YAML exceptions are identical, so we use a mixin. 183 /// 184 /// See_Also: MarkedYAMLException 185 template MarkedExceptionCtors() 186 { 187 public: 188 this(string msg, const Mark mark1, string mark2Label, 189 const Mark mark2, string file = __FILE__, size_t line = __LINE__) 190 @safe pure nothrow 191 { 192 super(msg, mark1, mark2Label, Nullable!Mark(mark2), file, line); 193 } 194 195 this(string msg, const Mark mark, 196 string file = __FILE__, size_t line = __LINE__) 197 @safe pure nothrow 198 { 199 super(msg, mark, file, line); 200 } 201 this(string msg, const Mark mark1, string mark2Label, 202 const Nullable!Mark mark2, string file = __FILE__, size_t line = __LINE__) 203 @safe pure nothrow 204 { 205 super(msg, mark1, mark2Label, mark2, file, line); 206 } 207 }