@@ -29,15 +29,6 @@ import dyaml.resolver;
29
29
30
30
31
31
package :
32
- /**
33
- * Exception thrown at composer errors.
34
- *
35
- * See_Also: MarkedYAMLException
36
- */
37
- class ComposerException : MarkedYAMLException
38
- {
39
- mixin MarkedExceptionCtors;
40
- }
41
32
42
33
// /Composes YAML documents from events provided by a Parser.
43
34
struct Composer
@@ -70,7 +61,7 @@ struct Composer
70
61
* Params: parser = Parser to provide YAML events.
71
62
* resolver = Resolver to resolve tags (data types).
72
63
*/
73
- this (Parser parser, Resolver resolver) @safe
64
+ this (Parser parser, Resolver resolver) @safe nothrow
74
65
{
75
66
parser_ = parser;
76
67
resolver_ = resolver;
@@ -102,9 +93,14 @@ struct Composer
102
93
}
103
94
104
95
// / Set file name.
105
- void name (string name) @safe pure nothrow @nogc
96
+ ref inout (string ) name () inout @safe return pure nothrow @nogc
97
+ {
98
+ return parser_.name;
99
+ }
100
+ // / Get a mark from the current reader position
101
+ Mark mark () const @safe pure nothrow @nogc
106
102
{
107
- parser_.name = name ;
103
+ return parser_.mark ;
108
104
}
109
105
110
106
// / Get resolver
@@ -169,8 +165,8 @@ struct Composer
169
165
// it's not finished, i.e. we're currently composing it
170
166
// and trying to use it recursively here.
171
167
enforce(anchors_[anchor] != Node(),
172
- new ComposerException (" Found recursive alias: " ~ anchor,
173
- event .startMark));
168
+ new ComposerException (text( " Found recursive alias: " , anchor) ,
169
+ event.startMark, " defined here " , anchors_[anchor] .startMark));
174
170
175
171
return anchors_[anchor];
176
172
}
@@ -179,16 +175,18 @@ struct Composer
179
175
const anchor = event.anchor;
180
176
if ((anchor ! is null ) && (anchor in anchors_) ! is null )
181
177
{
182
- throw new ComposerException(" Found duplicate anchor: " ~ anchor,
183
- event .startMark);
178
+ throw new ComposerException(text( " Found duplicate anchor: " , anchor) ,
179
+ event.startMark, " defined here " , anchors_[anchor] .startMark);
184
180
}
185
181
186
182
Node result;
187
183
// Associate the anchor, if any, with an uninitialized node.
188
184
// used to detect duplicate and recursive anchors.
189
185
if (anchor ! is null )
190
186
{
191
- anchors_[anchor] = Node();
187
+ Node tempNode;
188
+ tempNode.startMark_ = event.startMark;
189
+ anchors_[anchor] = tempNode;
192
190
}
193
191
194
192
switch (parser_.front.id)
@@ -276,12 +274,10 @@ struct Composer
276
274
{
277
275
// this is Composer, but the code is related to Constructor.
278
276
throw new ConstructorException(" While constructing a mapping, " ~
279
- " expected a mapping or a list of " ~
280
- " mappings for merging, but found: " ~
281
- text(node.type) ~
282
- " NOTE: line/column shows topmost parent " ~
283
- " to which the content is being merged" ,
284
- startMark, endMark);
277
+ " expected a mapping or a list of " ~
278
+ " mappings for merging, but found: " ~
279
+ text(node.type),
280
+ endMark, " mapping started here" , startMark);
285
281
}
286
282
287
283
ensureAppendersExist(pairAppenderLevel, nodeAppenderLevel);
@@ -371,14 +367,14 @@ struct Composer
371
367
}
372
368
373
369
auto sorted = pairAppender.data.dup .sort! ((x,y) => x.key > y.key);
374
- if (sorted.length) {
370
+ if (sorted.length)
371
+ {
375
372
foreach (index, const ref value; sorted[0 .. $ - 1 ].enumerate)
376
- if (value.key == sorted[index + 1 ].key) {
377
- const message = () @trusted {
378
- return format (" Key '%s' appears multiple times in mapping (first: %s)" ,
379
- value.key.get ! string , value.key.startMark);
380
- }();
381
- throw new ComposerException(message, sorted[index + 1 ].key.startMark);
373
+ if (value.key == sorted[index + 1 ].key)
374
+ {
375
+ throw new ComposerException(
376
+ text(" Key '" , value.key.get ! string , " ' appears multiple times in mapping" ),
377
+ sorted[index + 1 ].key.startMark, " defined here" , value.key.startMark);
382
378
}
383
379
}
384
380
@@ -403,10 +399,73 @@ struct Composer
403
399
"comment": "To write down comments pre-JSON5"
404
400
}` ;
405
401
406
- try
407
- auto node = Loader.fromString(str).load();
408
- catch (ComposerException exc)
409
- assert (exc.message() ==
410
- " Key 'comment' appears multiple times in mapping " ~
411
- " (first: file <unknown>,line 2,column 5)\n file <unknown>,line 4,column 5" );
402
+ const exc = collectException! LoaderException(Loader.fromString(str).load());
403
+ assert (exc);
404
+ assert (exc.message() ==
405
+ " Unable to load <unknown>: Key 'comment' appears multiple times in mapping\n " ~
406
+ " <unknown>:4,5\n defined here: <unknown>:2,5" );
407
+ }
408
+
409
+ // Provide good error message on duplicate anchors
410
+ @safe unittest
411
+ {
412
+ import dyaml.loader : Loader;
413
+
414
+ const str = ` {
415
+ a: &anchor b,
416
+ b: &anchor c,
417
+ }` ;
418
+
419
+ const exc = collectException! LoaderException(Loader.fromString(str).load());
420
+ assert (exc);
421
+ assert (exc.message() ==
422
+ " Unable to load <unknown>: Found duplicate anchor: anchor\n " ~
423
+ " <unknown>:3,8\n defined here: <unknown>:2,8" );
424
+ }
425
+
426
+ // Provide good error message on missing alias
427
+ @safe unittest
428
+ {
429
+ import dyaml.loader : Loader;
430
+
431
+ const str = ` {
432
+ a: *anchor,
433
+ }` ;
434
+
435
+ const exc = collectException! LoaderException(Loader.fromString(str).load());
436
+ assert (exc);
437
+ assert (exc.message() ==
438
+ " Unable to load <unknown>: Found undefined alias: anchor\n " ~
439
+ " <unknown>:2,8" );
440
+ }
441
+
442
+ // Provide good error message on recursive alias
443
+ @safe unittest
444
+ {
445
+ import dyaml.loader : Loader;
446
+
447
+ const str = ` a: &anchor {
448
+ b: *anchor
449
+ }` ;
450
+
451
+ const exc = collectException! LoaderException(Loader.fromString(str).load());
452
+ assert (exc);
453
+ assert (exc.message() ==
454
+ " Unable to load <unknown>: Found recursive alias: anchor\n " ~
455
+ " <unknown>:2,8\n defined here: <unknown>:1,4" );
456
+ }
457
+
458
+ // Provide good error message on failed merges
459
+ @safe unittest
460
+ {
461
+ import dyaml.loader : Loader;
462
+
463
+ const str = ` a: &anchor 3
464
+ b: { <<: *anchor }` ;
465
+
466
+ const exc = collectException! LoaderException(Loader.fromString(str).load());
467
+ assert (exc);
468
+ assert (exc.message() ==
469
+ " Unable to load <unknown>: While constructing a mapping, expected a mapping or a list of mappings for merging, but found: integer\n " ~
470
+ " <unknown>:2,19\n mapping started here: <unknown>:2,4" );
412
471
}
0 commit comments