major attribute fixing
This commit is contained in:
parent
d60db0c7df
commit
6088f0b632
|
@ -232,7 +232,7 @@ final class Composer
|
||||||
}
|
}
|
||||||
|
|
||||||
///Compose a scalar node.
|
///Compose a scalar node.
|
||||||
Node composeScalarNode() @system
|
Node composeScalarNode() @safe
|
||||||
{
|
{
|
||||||
immutable event = parser_.getEvent();
|
immutable event = parser_.getEvent();
|
||||||
const tag = resolver_.resolve(NodeID.Scalar, event.tag, event.value,
|
const tag = resolver_.resolve(NodeID.Scalar, event.tag, event.value,
|
||||||
|
@ -263,9 +263,7 @@ final class Composer
|
||||||
nodeAppender.put(composeNode(pairAppenderLevel, nodeAppenderLevel + 1));
|
nodeAppender.put(composeNode(pairAppenderLevel, nodeAppenderLevel + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
core.memory.GC.disable();
|
Node node = constructor_.node(startEvent.startMark, parser_.getEvent().endMark,
|
||||||
scope(exit){core.memory.GC.enable();}
|
|
||||||
Node node = constructor_.node(startEvent.startMark, parser_.getEvent().endMark,
|
|
||||||
tag, nodeAppender.data.dup, startEvent.collectionStyle);
|
tag, nodeAppender.data.dup, startEvent.collectionStyle);
|
||||||
nodeAppender.clear();
|
nodeAppender.clear();
|
||||||
|
|
||||||
|
@ -286,7 +284,7 @@ final class Composer
|
||||||
* Returns: Flattened mapping as pairs.
|
* Returns: Flattened mapping as pairs.
|
||||||
*/
|
*/
|
||||||
Node.Pair[] flatten(ref Node root, const Mark startMark, const Mark endMark,
|
Node.Pair[] flatten(ref Node root, const Mark startMark, const Mark endMark,
|
||||||
const uint pairAppenderLevel, const uint nodeAppenderLevel) @system
|
const uint pairAppenderLevel, const uint nodeAppenderLevel) @safe
|
||||||
{
|
{
|
||||||
void error(Node node)
|
void error(Node node)
|
||||||
{
|
{
|
||||||
|
@ -306,11 +304,11 @@ final class Composer
|
||||||
if(root.isMapping)
|
if(root.isMapping)
|
||||||
{
|
{
|
||||||
Node[] toMerge;
|
Node[] toMerge;
|
||||||
|
toMerge.reserve(root.length);
|
||||||
foreach(ref Node key, ref Node value; root)
|
foreach(ref Node key, ref Node value; root)
|
||||||
{
|
{
|
||||||
if(key.isType!YAMLMerge)
|
if(key.isType!YAMLMerge)
|
||||||
{
|
{
|
||||||
toMerge.assumeSafeAppend();
|
|
||||||
toMerge ~= value;
|
toMerge ~= value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -337,8 +335,6 @@ final class Composer
|
||||||
error(root);
|
error(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
core.memory.GC.disable();
|
|
||||||
scope(exit){core.memory.GC.enable();}
|
|
||||||
auto flattened = pairAppender.data.dup;
|
auto flattened = pairAppender.data.dup;
|
||||||
pairAppender.clear();
|
pairAppender.clear();
|
||||||
|
|
||||||
|
@ -381,9 +377,7 @@ final class Composer
|
||||||
pairAppenderLevel + 1, nodeAppenderLevel));
|
pairAppenderLevel + 1, nodeAppenderLevel));
|
||||||
}
|
}
|
||||||
|
|
||||||
core.memory.GC.disable();
|
Node node = constructor_.node(startEvent.startMark, parser_.getEvent().endMark,
|
||||||
scope(exit){core.memory.GC.enable();}
|
|
||||||
Node node = constructor_.node(startEvent.startMark, parser_.getEvent().endMark,
|
|
||||||
tag, pairAppender.data.dup, startEvent.collectionStyle);
|
tag, pairAppender.data.dup, startEvent.collectionStyle);
|
||||||
|
|
||||||
pairAppender.clear();
|
pairAppender.clear();
|
||||||
|
|
|
@ -182,7 +182,6 @@ final class Constructor
|
||||||
* --------------------
|
* --------------------
|
||||||
*/
|
*/
|
||||||
void addConstructorScalar(T)(const string tag, T function(ref Node) ctor)
|
void addConstructorScalar(T)(const string tag, T function(ref Node) ctor)
|
||||||
@safe nothrow
|
|
||||||
{
|
{
|
||||||
const t = tag;
|
const t = tag;
|
||||||
auto deleg = addConstructor!T(t, ctor);
|
auto deleg = addConstructor!T(t, ctor);
|
||||||
|
@ -233,7 +232,6 @@ final class Constructor
|
||||||
* --------------------
|
* --------------------
|
||||||
*/
|
*/
|
||||||
void addConstructorSequence(T)(const string tag, T function(ref Node) ctor)
|
void addConstructorSequence(T)(const string tag, T function(ref Node) ctor)
|
||||||
@safe nothrow
|
|
||||||
{
|
{
|
||||||
const t = tag;
|
const t = tag;
|
||||||
auto deleg = addConstructor!T(t, ctor);
|
auto deleg = addConstructor!T(t, ctor);
|
||||||
|
@ -284,7 +282,6 @@ final class Constructor
|
||||||
* --------------------
|
* --------------------
|
||||||
*/
|
*/
|
||||||
void addConstructorMapping(T)(const string tag, T function(ref Node) ctor)
|
void addConstructorMapping(T)(const string tag, T function(ref Node) ctor)
|
||||||
@safe nothrow
|
|
||||||
{
|
{
|
||||||
const t = tag;
|
const t = tag;
|
||||||
auto deleg = addConstructor!T(t, ctor);
|
auto deleg = addConstructor!T(t, ctor);
|
||||||
|
@ -346,7 +343,6 @@ final class Constructor
|
||||||
* ctor = Constructor function.
|
* ctor = Constructor function.
|
||||||
*/
|
*/
|
||||||
auto addConstructor(T)(const string tag, T function(ref Node) ctor)
|
auto addConstructor(T)(const string tag, T function(ref Node) ctor)
|
||||||
@safe nothrow
|
|
||||||
{
|
{
|
||||||
assert((tag in fromScalar_) is null &&
|
assert((tag in fromScalar_) is null &&
|
||||||
(tag in fromSequence_) is null &&
|
(tag in fromSequence_) is null &&
|
||||||
|
@ -363,7 +359,7 @@ final class Constructor
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get the array of constructor functions for scalar, sequence or mapping.
|
//Get the array of constructor functions for scalar, sequence or mapping.
|
||||||
@property auto delegates(T)() @safe pure nothrow @nogc
|
@property auto delegates(T)()
|
||||||
{
|
{
|
||||||
static if(is(T : string)) {return &fromScalar_;}
|
static if(is(T : string)) {return &fromScalar_;}
|
||||||
else static if(is(T : Node[])) {return &fromSequence_;}
|
else static if(is(T : Node[])) {return &fromSequence_;}
|
||||||
|
@ -397,7 +393,7 @@ bool constructBool(ref Node node) @safe
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct an integer (long) _node.
|
/// Construct an integer (long) _node.
|
||||||
long constructLong(ref Node node)
|
long constructLong(ref Node node) @safe
|
||||||
{
|
{
|
||||||
string value = node.as!string().replace("_", "");
|
string value = node.as!string().replace("_", "");
|
||||||
const char c = value[0];
|
const char c = value[0];
|
||||||
|
@ -442,9 +438,9 @@ long constructLong(ref Node node)
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
long getLong(string str)
|
long getLong(string str) @safe
|
||||||
{
|
{
|
||||||
auto node = Node(str);
|
auto node = Node(str);
|
||||||
return constructLong(node);
|
return constructLong(node);
|
||||||
|
@ -466,7 +462,7 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a floating point (real) _node.
|
/// Construct a floating point (real) _node.
|
||||||
real constructReal(ref Node node)
|
real constructReal(ref Node node) @safe
|
||||||
{
|
{
|
||||||
string value = node.as!string().replace("_", "").toLower();
|
string value = node.as!string().replace("_", "").toLower();
|
||||||
const char c = value[0];
|
const char c = value[0];
|
||||||
|
@ -508,14 +504,14 @@ real constructReal(ref Node node)
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
bool eq(real a, real b, real epsilon = 0.2)
|
bool eq(real a, real b, real epsilon = 0.2) @safe
|
||||||
{
|
{
|
||||||
return a >= (b - epsilon) && a <= (b + epsilon);
|
return a >= (b - epsilon) && a <= (b + epsilon);
|
||||||
}
|
}
|
||||||
|
|
||||||
real getReal(string str)
|
real getReal(string str) @safe
|
||||||
{
|
{
|
||||||
auto node = Node(str);
|
auto node = Node(str);
|
||||||
return constructReal(node);
|
return constructReal(node);
|
||||||
|
@ -537,7 +533,7 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a binary (base64) _node.
|
/// Construct a binary (base64) _node.
|
||||||
ubyte[] constructBinary(ref Node node)
|
ubyte[] constructBinary(ref Node node) @safe
|
||||||
{
|
{
|
||||||
import std.ascii : newline;
|
import std.ascii : newline;
|
||||||
import std.array : array;
|
import std.array : array;
|
||||||
|
@ -554,12 +550,12 @@ ubyte[] constructBinary(ref Node node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
ubyte[] test = cast(ubyte[])"The Answer: 42";
|
auto test = "The Answer: 42".representation;
|
||||||
char[] buffer;
|
char[] buffer;
|
||||||
buffer.length = 256;
|
buffer.length = 256;
|
||||||
string input = cast(string)Base64.encode(test, buffer);
|
string input = Base64.encode(test, buffer).idup;
|
||||||
auto node = Node(input);
|
auto node = Node(input);
|
||||||
auto value = constructBinary(node);
|
auto value = constructBinary(node);
|
||||||
assert(value == test);
|
assert(value == test);
|
||||||
|
@ -567,7 +563,7 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a timestamp (SysTime) _node.
|
/// Construct a timestamp (SysTime) _node.
|
||||||
SysTime constructTimestamp(ref Node node)
|
SysTime constructTimestamp(ref Node node) @safe
|
||||||
{
|
{
|
||||||
string value = node.as!string;
|
string value = node.as!string;
|
||||||
|
|
||||||
|
@ -639,7 +635,7 @@ SysTime constructTimestamp(ref Node node)
|
||||||
|
|
||||||
assert(false, "This code should never be reached");
|
assert(false, "This code should never be reached");
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML construction timestamp unittest");
|
writeln("D:YAML construction timestamp unittest");
|
||||||
|
|
||||||
|
@ -669,23 +665,22 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a string _node.
|
/// Construct a string _node.
|
||||||
string constructString(ref Node node)
|
string constructString(ref Node node) @safe
|
||||||
{
|
{
|
||||||
return node.as!string;
|
return node.as!string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a sequence of single-element mappings into a sequence of pairs.
|
/// Convert a sequence of single-element mappings into a sequence of pairs.
|
||||||
Node.Pair[] getPairs(string type, Node[] nodes)
|
Node.Pair[] getPairs(string type, Node[] nodes) @safe
|
||||||
{
|
{
|
||||||
Node.Pair[] pairs;
|
Node.Pair[] pairs;
|
||||||
|
pairs.reserve(nodes.length);
|
||||||
foreach(ref node; nodes)
|
foreach(ref node; nodes)
|
||||||
{
|
{
|
||||||
enforce(node.isMapping && node.length == 1,
|
enforce(node.isMapping && node.length == 1,
|
||||||
new Exception("While constructing " ~ type ~
|
new Exception("While constructing " ~ type ~
|
||||||
", expected a mapping with single element"));
|
", expected a mapping with single element"));
|
||||||
|
|
||||||
pairs.assumeSafeAppend();
|
|
||||||
pairs ~= node.as!(Node.Pair[]);
|
pairs ~= node.as!(Node.Pair[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,14 +688,13 @@ Node.Pair[] getPairs(string type, Node[] nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct an ordered map (ordered sequence of key:value pairs without duplicates) _node.
|
/// Construct an ordered map (ordered sequence of key:value pairs without duplicates) _node.
|
||||||
Node.Pair[] constructOrderedMap(ref Node node)
|
Node.Pair[] constructOrderedMap(ref Node node) @safe
|
||||||
{
|
{
|
||||||
auto pairs = getPairs("ordered map", node.as!(Node[]));
|
auto pairs = getPairs("ordered map", node.as!(Node[]));
|
||||||
|
|
||||||
//Detect duplicates.
|
//Detect duplicates.
|
||||||
//TODO this should be replaced by something with deterministic memory allocation.
|
//TODO this should be replaced by something with deterministic memory allocation.
|
||||||
auto keys = redBlackTree!Node();
|
auto keys = redBlackTree!Node();
|
||||||
scope(exit){keys.destroy();}
|
|
||||||
foreach(ref pair; pairs)
|
foreach(ref pair; pairs)
|
||||||
{
|
{
|
||||||
enforce(!(pair.key in keys),
|
enforce(!(pair.key in keys),
|
||||||
|
@ -710,37 +704,35 @@ Node.Pair[] constructOrderedMap(ref Node node)
|
||||||
}
|
}
|
||||||
return pairs;
|
return pairs;
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML construction ordered map unittest");
|
writeln("D:YAML construction ordered map unittest");
|
||||||
|
|
||||||
alias Node.Pair Pair;
|
alias Node.Pair Pair;
|
||||||
|
|
||||||
Node[] alternateTypes(uint length)
|
Node[] alternateTypes(uint length) @safe
|
||||||
{
|
{
|
||||||
Node[] pairs;
|
Node[] pairs;
|
||||||
foreach(long i; 0 .. length)
|
foreach(long i; 0 .. length)
|
||||||
{
|
{
|
||||||
auto pair = (i % 2) ? Pair(i.to!string, i) : Pair(i, i.to!string);
|
auto pair = (i % 2) ? Pair(i.to!string, i) : Pair(i, i.to!string);
|
||||||
pairs.assumeSafeAppend();
|
|
||||||
pairs ~= Node([pair]);
|
pairs ~= Node([pair]);
|
||||||
}
|
}
|
||||||
return pairs;
|
return pairs;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] sameType(uint length)
|
Node[] sameType(uint length) @safe
|
||||||
{
|
{
|
||||||
Node[] pairs;
|
Node[] pairs;
|
||||||
foreach(long i; 0 .. length)
|
foreach(long i; 0 .. length)
|
||||||
{
|
{
|
||||||
auto pair = Pair(i.to!string, i);
|
auto pair = Pair(i.to!string, i);
|
||||||
pairs.assumeSafeAppend();
|
|
||||||
pairs ~= Node([pair]);
|
pairs ~= Node([pair]);
|
||||||
}
|
}
|
||||||
return pairs;
|
return pairs;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasDuplicates(Node[] nodes)
|
bool hasDuplicates(Node[] nodes) @safe
|
||||||
{
|
{
|
||||||
auto node = Node(nodes);
|
auto node = Node(nodes);
|
||||||
return null !is collectException(constructOrderedMap(node));
|
return null !is collectException(constructOrderedMap(node));
|
||||||
|
@ -755,13 +747,13 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a pairs (ordered sequence of key: value pairs allowing duplicates) _node.
|
/// Construct a pairs (ordered sequence of key: value pairs allowing duplicates) _node.
|
||||||
Node.Pair[] constructPairs(ref Node node)
|
Node.Pair[] constructPairs(ref Node node) @safe
|
||||||
{
|
{
|
||||||
return getPairs("pairs", node.as!(Node[]));
|
return getPairs("pairs", node.as!(Node[]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a set _node.
|
/// Construct a set _node.
|
||||||
Node[] constructSet(ref Node node)
|
Node[] constructSet(ref Node node) @safe
|
||||||
{
|
{
|
||||||
auto pairs = node.as!(Node.Pair[]);
|
auto pairs = node.as!(Node.Pair[]);
|
||||||
|
|
||||||
|
@ -769,28 +761,26 @@ Node[] constructSet(ref Node node)
|
||||||
// memory allocation if possible.
|
// memory allocation if possible.
|
||||||
// Detect duplicates.
|
// Detect duplicates.
|
||||||
ubyte[Node] map;
|
ubyte[Node] map;
|
||||||
scope(exit){map.destroy();}
|
|
||||||
Node[] nodes;
|
Node[] nodes;
|
||||||
|
nodes.reserve(pairs.length);
|
||||||
foreach(ref pair; pairs)
|
foreach(ref pair; pairs)
|
||||||
{
|
{
|
||||||
enforce((pair.key in map) is null, new Exception("Duplicate entry in a set"));
|
enforce((pair.key in map) is null, new Exception("Duplicate entry in a set"));
|
||||||
map[pair.key] = 0;
|
map[pair.key] = 0;
|
||||||
nodes.assumeSafeAppend();
|
|
||||||
nodes ~= pair.key;
|
nodes ~= pair.key;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML construction set unittest");
|
writeln("D:YAML construction set unittest");
|
||||||
|
|
||||||
Node.Pair[] set(uint length)
|
Node.Pair[] set(uint length) @safe
|
||||||
{
|
{
|
||||||
Node.Pair[] pairs;
|
Node.Pair[] pairs;
|
||||||
foreach(long i; 0 .. length)
|
foreach(long i; 0 .. length)
|
||||||
{
|
{
|
||||||
pairs.assumeSafeAppend();
|
|
||||||
pairs ~= Node.Pair(i.to!string, YAMLNull());
|
pairs ~= Node.Pair(i.to!string, YAMLNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,19 +817,18 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a sequence (array) _node.
|
/// Construct a sequence (array) _node.
|
||||||
Node[] constructSequence(ref Node node)
|
Node[] constructSequence(ref Node node) @safe
|
||||||
{
|
{
|
||||||
return node.as!(Node[]);
|
return node.as!(Node[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct an unordered map (unordered set of key:value _pairs without duplicates) _node.
|
/// Construct an unordered map (unordered set of key:value _pairs without duplicates) _node.
|
||||||
Node.Pair[] constructMap(ref Node node)
|
Node.Pair[] constructMap(ref Node node) @safe
|
||||||
{
|
{
|
||||||
auto pairs = node.as!(Node.Pair[]);
|
auto pairs = node.as!(Node.Pair[]);
|
||||||
//Detect duplicates.
|
//Detect duplicates.
|
||||||
//TODO this should be replaced by something with deterministic memory allocation.
|
//TODO this should be replaced by something with deterministic memory allocation.
|
||||||
auto keys = redBlackTree!Node();
|
auto keys = redBlackTree!Node();
|
||||||
scope(exit){keys.destroy();}
|
|
||||||
foreach(ref pair; pairs)
|
foreach(ref pair; pairs)
|
||||||
{
|
{
|
||||||
enforce(!(pair.key in keys),
|
enforce(!(pair.key in keys),
|
||||||
|
@ -868,26 +857,26 @@ struct MyStruct
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MyStruct constructMyStructScalar(ref Node node)
|
MyStruct constructMyStructScalar(ref Node node) @safe
|
||||||
{
|
{
|
||||||
// Guaranteed to be string as we construct from scalar.
|
// Guaranteed to be string as we construct from scalar.
|
||||||
auto parts = node.as!string().split(":");
|
auto parts = node.as!string().split(":");
|
||||||
return MyStruct(to!int(parts[0]), to!int(parts[1]), to!int(parts[2]));
|
return MyStruct(to!int(parts[0]), to!int(parts[1]), to!int(parts[2]));
|
||||||
}
|
}
|
||||||
|
|
||||||
MyStruct constructMyStructSequence(ref Node node)
|
MyStruct constructMyStructSequence(ref Node node) @safe
|
||||||
{
|
{
|
||||||
// node is guaranteed to be sequence.
|
// node is guaranteed to be sequence.
|
||||||
return MyStruct(node[0].as!int, node[1].as!int, node[2].as!int);
|
return MyStruct(node[0].as!int, node[1].as!int, node[2].as!int);
|
||||||
}
|
}
|
||||||
|
|
||||||
MyStruct constructMyStructMapping(ref Node node)
|
MyStruct constructMyStructMapping(ref Node node) @safe
|
||||||
{
|
{
|
||||||
// node is guaranteed to be mapping.
|
// node is guaranteed to be mapping.
|
||||||
return MyStruct(node["x"].as!int, node["y"].as!int, node["z"].as!int);
|
return MyStruct(node["x"].as!int, node["y"].as!int, node["z"].as!int);
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
char[] data = "!mystruct 1:2:3".dup;
|
char[] data = "!mystruct 1:2:3".dup;
|
||||||
auto loader = Loader(data);
|
auto loader = Loader(data);
|
||||||
|
@ -899,7 +888,7 @@ unittest
|
||||||
assert(node.as!MyStruct == MyStruct(1, 2, 3));
|
assert(node.as!MyStruct == MyStruct(1, 2, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
char[] data = "!mystruct [1, 2, 3]".dup;
|
char[] data = "!mystruct [1, 2, 3]".dup;
|
||||||
auto loader = Loader(data);
|
auto loader = Loader(data);
|
||||||
|
@ -911,7 +900,7 @@ unittest
|
||||||
assert(node.as!MyStruct == MyStruct(1, 2, 3));
|
assert(node.as!MyStruct == MyStruct(1, 2, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
char[] data = "!mystruct {x: 1, y: 2, z: 3}".dup;
|
char[] data = "!mystruct {x: 1, y: 2, z: 3}".dup;
|
||||||
auto loader = Loader(data);
|
auto loader = Loader(data);
|
||||||
|
|
|
@ -80,28 +80,28 @@ import dyaml.tagdirective;
|
||||||
*/
|
*/
|
||||||
struct Dumper
|
struct Dumper
|
||||||
{
|
{
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
auto node = Node([1, 2, 3, 4, 5]);
|
auto node = Node([1, 2, 3, 4, 5]);
|
||||||
Dumper(new YMemoryStream()).dump(node);
|
Dumper(new YMemoryStream()).dump(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
auto node1 = Node([1, 2, 3, 4, 5]);
|
auto node1 = Node([1, 2, 3, 4, 5]);
|
||||||
auto node2 = Node("This document contains only one string");
|
auto node2 = Node("This document contains only one string");
|
||||||
Dumper(new YMemoryStream()).dump(node1, node2);
|
Dumper(new YMemoryStream()).dump(node1, node2);
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
//import std.stream;
|
//import std.stream;
|
||||||
auto stream = new YMemoryStream();
|
auto stream = new YMemoryStream();
|
||||||
auto node = Node([1, 2, 3, 4, 5]);
|
auto node = Node([1, 2, 3, 4, 5]);
|
||||||
Dumper(stream).dump(node);
|
Dumper(stream).dump(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
auto node = Node([1, 2, 3, 4, 5]);
|
auto node = Node([1, 2, 3, 4, 5]);
|
||||||
auto representer = new Representer();
|
auto representer = new Representer();
|
||||||
|
@ -157,7 +157,7 @@ struct Dumper
|
||||||
*
|
*
|
||||||
* Throws: YAMLException if the file can not be dumped to (e.g. cannot be opened).
|
* Throws: YAMLException if the file can not be dumped to (e.g. cannot be opened).
|
||||||
*/
|
*/
|
||||||
this(string filename) @trusted
|
this(string filename) @safe
|
||||||
{
|
{
|
||||||
name_ = filename;
|
name_ = filename;
|
||||||
//try{this(new File(filename, FileMode.OutNew));}
|
//try{this(new File(filename, FileMode.OutNew));}
|
||||||
|
@ -183,7 +183,6 @@ struct Dumper
|
||||||
///Destroy the Dumper.
|
///Destroy the Dumper.
|
||||||
@trusted ~this()
|
@trusted ~this()
|
||||||
{
|
{
|
||||||
YAMLVersion_ = null;
|
|
||||||
if(weOwnStream_) { destroy(stream_); }
|
if(weOwnStream_) { destroy(stream_); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,16 +193,14 @@ struct Dumper
|
||||||
}
|
}
|
||||||
|
|
||||||
///Specify custom Resolver to use.
|
///Specify custom Resolver to use.
|
||||||
@property void resolver(Resolver resolver) @trusted
|
@property void resolver(Resolver resolver) @safe
|
||||||
{
|
{
|
||||||
resolver_.destroy();
|
|
||||||
resolver_ = resolver;
|
resolver_ = resolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
///Specify custom Representer to use.
|
///Specify custom Representer to use.
|
||||||
@property void representer(Representer representer) @trusted
|
@property void representer(Representer representer) @safe
|
||||||
{
|
{
|
||||||
representer_.destroy();
|
|
||||||
representer_ = representer;
|
representer_ = representer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,7 +287,7 @@ struct Dumper
|
||||||
* dumper.dump(Node("foo"));
|
* dumper.dump(Node("foo"));
|
||||||
* --------------------
|
* --------------------
|
||||||
*/
|
*/
|
||||||
@property void tagDirectives(string[string] tags) pure @trusted
|
@property void tagDirectives(string[string] tags) pure @safe
|
||||||
{
|
{
|
||||||
TagDirective[] t;
|
TagDirective[] t;
|
||||||
foreach(handle, prefix; tags)
|
foreach(handle, prefix; tags)
|
||||||
|
|
|
@ -184,21 +184,6 @@ struct Emitter
|
||||||
analysis_.flags.isNull = true;
|
analysis_.flags.isNull = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
///Destroy the emitter.
|
|
||||||
@trusted ~this()
|
|
||||||
{
|
|
||||||
stream_ = null;
|
|
||||||
states_.destroy();
|
|
||||||
events_.destroy();
|
|
||||||
indents_.destroy();
|
|
||||||
tagDirectives_.destroy();
|
|
||||||
tagDirectives_ = null;
|
|
||||||
preparedAnchor_.destroy();
|
|
||||||
preparedAnchor_ = null;
|
|
||||||
preparedTag_.destroy();
|
|
||||||
preparedTag_ = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
///Emit an event. Throws EmitterException on error.
|
///Emit an event. Throws EmitterException on error.
|
||||||
void emit(Event event) @trusted
|
void emit(Event event) @trusted
|
||||||
{
|
{
|
||||||
|
@ -237,20 +222,20 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Write a string to the file/stream.
|
///Write a string to the file/stream.
|
||||||
void writeString(const string str) @system
|
void writeString(const char[] str) @safe
|
||||||
{
|
{
|
||||||
try final switch(encoding_)
|
try final switch(encoding_)
|
||||||
{
|
{
|
||||||
case Encoding.UTF_8:
|
case Encoding.UTF_8:
|
||||||
stream_.writeExact(str.ptr, str.length * char.sizeof);
|
stream_.writeExact(str);
|
||||||
break;
|
break;
|
||||||
case Encoding.UTF_16:
|
case Encoding.UTF_16:
|
||||||
const buffer = to!wstring(str);
|
const buffer = to!wstring(str);
|
||||||
stream_.writeExact(buffer.ptr, buffer.length * wchar.sizeof);
|
stream_.writeExact(buffer);
|
||||||
break;
|
break;
|
||||||
case Encoding.UTF_32:
|
case Encoding.UTF_32:
|
||||||
const buffer = to!dstring(str);
|
const buffer = to!dstring(str);
|
||||||
stream_.writeExact(buffer.ptr, buffer.length * dchar.sizeof);
|
stream_.writeExact(buffer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
|
@ -260,7 +245,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///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() @trusted nothrow
|
bool needMoreEvents() @safe nothrow
|
||||||
{
|
{
|
||||||
if(events_.length == 0){return true;}
|
if(events_.length == 0){return true;}
|
||||||
|
|
||||||
|
@ -273,7 +258,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Determines if we need specified number of more events.
|
///Determines if we need specified number of more events.
|
||||||
bool needEvents(in uint count) @system nothrow
|
bool needEvents(in uint count) @safe nothrow
|
||||||
{
|
{
|
||||||
int level = 0;
|
int level = 0;
|
||||||
|
|
||||||
|
@ -315,7 +300,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///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 @trusted
|
bool eventTypeIs(in EventID id) const pure @safe
|
||||||
{
|
{
|
||||||
enforce(!event_.isNull,
|
enforce(!event_.isNull,
|
||||||
new Error("Expected an event, but no event is available."));
|
new Error("Expected an event, but no event is available."));
|
||||||
|
@ -340,7 +325,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Expect nothing, throwing if we still have something.
|
///Expect nothing, throwing if we still have something.
|
||||||
void expectNothing() const @trusted
|
void expectNothing() const @safe
|
||||||
{
|
{
|
||||||
throw new Error("Expected nothing, but got " ~ event_.idString);
|
throw new Error("Expected nothing, but got " ~ event_.idString);
|
||||||
}
|
}
|
||||||
|
@ -452,7 +437,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Handle a new node. Context specifies where in the document we are.
|
///Handle a new node. Context specifies where in the document we are.
|
||||||
void expectNode(const Context context) @trusted
|
void expectNode(const Context context) @safe
|
||||||
{
|
{
|
||||||
context_ = context;
|
context_ = context;
|
||||||
|
|
||||||
|
@ -504,7 +489,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Handle a scalar.
|
///Handle a scalar.
|
||||||
void expectScalar() @trusted
|
void expectScalar() @safe
|
||||||
{
|
{
|
||||||
increaseIndent(Yes.flow);
|
increaseIndent(Yes.flow);
|
||||||
processScalar();
|
processScalar();
|
||||||
|
@ -835,7 +820,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Determine style to write the current scalar in.
|
///Determine style to write the current scalar in.
|
||||||
ScalarStyle chooseScalarStyle() @trusted
|
ScalarStyle chooseScalarStyle() @safe
|
||||||
{
|
{
|
||||||
if(analysis_.flags.isNull){analysis_ = analyzeScalar(event_.value);}
|
if(analysis_.flags.isNull){analysis_ = analyzeScalar(event_.value);}
|
||||||
|
|
||||||
|
@ -878,7 +863,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Prepare YAML version string for output.
|
///Prepare YAML version string for output.
|
||||||
static string prepareVersion(const string YAMLVersion) @trusted
|
static string prepareVersion(const string YAMLVersion) @safe
|
||||||
{
|
{
|
||||||
enforce(YAMLVersion.split(".")[0] == "1",
|
enforce(YAMLVersion.split(".")[0] == "1",
|
||||||
new Error("Unsupported YAML version: " ~ YAMLVersion));
|
new Error("Unsupported YAML version: " ~ YAMLVersion));
|
||||||
|
@ -886,7 +871,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Encode an Unicode character for tag directive and write it to writer.
|
///Encode an Unicode character for tag directive and write it to writer.
|
||||||
static void encodeChar(Writer)(ref Writer writer, in dchar c) @trusted
|
static void encodeChar(Writer)(ref Writer writer, in dchar c) @safe
|
||||||
{
|
{
|
||||||
char[4] data;
|
char[4] data;
|
||||||
const bytes = encode(data, c);
|
const bytes = encode(data, c);
|
||||||
|
@ -898,7 +883,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Prepare tag directive handle for output.
|
///Prepare tag directive handle for output.
|
||||||
static string prepareTagHandle(const string handle) @trusted
|
static string prepareTagHandle(const string handle) @safe
|
||||||
{
|
{
|
||||||
enforce(handle !is null && handle != "",
|
enforce(handle !is null && handle != "",
|
||||||
new Error("Tag handle must not be empty"));
|
new Error("Tag handle must not be empty"));
|
||||||
|
@ -913,7 +898,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Prepare tag directive prefix for output.
|
///Prepare tag directive prefix for output.
|
||||||
static string prepareTagPrefix(const string prefix) @trusted
|
static string prepareTagPrefix(const string prefix) @safe
|
||||||
{
|
{
|
||||||
enforce(prefix !is null && prefix != "",
|
enforce(prefix !is null && prefix != "",
|
||||||
new Error("Tag prefix must not be empty"));
|
new Error("Tag prefix must not be empty"));
|
||||||
|
@ -944,7 +929,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Prepare tag for output.
|
///Prepare tag for output.
|
||||||
string prepareTag(in string tag) @trusted
|
string prepareTag(in string tag) @safe
|
||||||
{
|
{
|
||||||
enforce(tag !is null, new Error("Tag must not be empty"));
|
enforce(tag !is null, new Error("Tag must not be empty"));
|
||||||
|
|
||||||
|
@ -991,7 +976,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Prepare anchor for output.
|
///Prepare anchor for output.
|
||||||
static string prepareAnchor(const string anchor) @trusted
|
static string prepareAnchor(const string anchor) @safe
|
||||||
{
|
{
|
||||||
enforce(anchor != "",
|
enforce(anchor != "",
|
||||||
new Error("Anchor must not be empty"));
|
new Error("Anchor must not be empty"));
|
||||||
|
@ -1172,7 +1157,7 @@ struct Emitter
|
||||||
//Writers.
|
//Writers.
|
||||||
|
|
||||||
///Start the YAML stream (write the unicode byte order mark).
|
///Start the YAML stream (write the unicode byte order mark).
|
||||||
void writeStreamStart() @system
|
void writeStreamStart() @safe
|
||||||
{
|
{
|
||||||
immutable(ubyte)[] bom;
|
immutable(ubyte)[] bom;
|
||||||
//Write BOM (except for UTF-8)
|
//Write BOM (except for UTF-8)
|
||||||
|
@ -1196,13 +1181,13 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///End the YAML stream.
|
///End the YAML stream.
|
||||||
void writeStreamEnd() @system {stream_.flush();}
|
void writeStreamEnd() @safe {stream_.flush();}
|
||||||
|
|
||||||
///Write an indicator (e.g. ":", "[", ">", etc.).
|
///Write an indicator (e.g. ":", "[", ">", etc.).
|
||||||
void writeIndicator(const string indicator,
|
void writeIndicator(const char[] indicator,
|
||||||
const Flag!"needWhitespace" needWhitespace,
|
const Flag!"needWhitespace" needWhitespace,
|
||||||
const Flag!"whitespace" whitespace = No.whitespace,
|
const Flag!"whitespace" whitespace = No.whitespace,
|
||||||
const Flag!"indentation" indentation = No.indentation) @system
|
const Flag!"indentation" indentation = No.indentation) @safe
|
||||||
{
|
{
|
||||||
const bool prefixSpace = !whitespace_ && needWhitespace;
|
const bool prefixSpace = !whitespace_ && needWhitespace;
|
||||||
whitespace_ = whitespace;
|
whitespace_ = whitespace;
|
||||||
|
@ -1218,7 +1203,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Write indentation.
|
///Write indentation.
|
||||||
void writeIndent() @system
|
void writeIndent() @safe
|
||||||
{
|
{
|
||||||
const indent = indent_ == -1 ? 0 : indent_;
|
const indent = indent_ == -1 ? 0 : indent_;
|
||||||
|
|
||||||
|
@ -1244,7 +1229,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Start new line.
|
///Start new line.
|
||||||
void writeLineBreak(const string data = null) @system
|
void writeLineBreak(const char[] data = null) @safe
|
||||||
{
|
{
|
||||||
whitespace_ = indentation_ = true;
|
whitespace_ = indentation_ = true;
|
||||||
++line_;
|
++line_;
|
||||||
|
@ -1253,7 +1238,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Write a YAML version directive.
|
///Write a YAML version directive.
|
||||||
void writeVersionDirective(const string versionText) @system
|
void writeVersionDirective(const string versionText) @safe
|
||||||
{
|
{
|
||||||
writeString("%YAML ");
|
writeString("%YAML ");
|
||||||
writeString(versionText);
|
writeString(versionText);
|
||||||
|
@ -1261,7 +1246,7 @@ struct Emitter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Write a tag directive.
|
///Write a tag directive.
|
||||||
void writeTagDirective(const string handle, const string prefix) @system
|
void writeTagDirective(const string handle, const string prefix) @safe
|
||||||
{
|
{
|
||||||
writeString("%TAG ");
|
writeString("%TAG ");
|
||||||
writeString(handle);
|
writeString(handle);
|
||||||
|
@ -1319,14 +1304,8 @@ struct ScalarWriter
|
||||||
split_ = split;
|
split_ = split;
|
||||||
}
|
}
|
||||||
|
|
||||||
///Destroy the ScalarWriter.
|
|
||||||
@trusted nothrow ~this()
|
|
||||||
{
|
|
||||||
text_ = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
///Write text as single quoted scalar.
|
///Write text as single quoted scalar.
|
||||||
void writeSingleQuoted() @system
|
void writeSingleQuoted() @safe
|
||||||
{
|
{
|
||||||
emitter_.writeIndicator("\'", Yes.needWhitespace);
|
emitter_.writeIndicator("\'", Yes.needWhitespace);
|
||||||
spaces_ = breaks_ = false;
|
spaces_ = breaks_ = false;
|
||||||
|
@ -1376,7 +1355,7 @@ struct ScalarWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Write text as double quoted scalar.
|
///Write text as double quoted scalar.
|
||||||
void writeDoubleQuoted() @system
|
void writeDoubleQuoted() @safe
|
||||||
{
|
{
|
||||||
resetTextPosition();
|
resetTextPosition();
|
||||||
emitter_.writeIndicator("\"", Yes.needWhitespace);
|
emitter_.writeIndicator("\"", Yes.needWhitespace);
|
||||||
|
@ -1438,7 +1417,7 @@ struct ScalarWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Write text as folded block scalar.
|
///Write text as folded block scalar.
|
||||||
void writeFolded() @system
|
void writeFolded() @safe
|
||||||
{
|
{
|
||||||
initBlock('>');
|
initBlock('>');
|
||||||
bool leadingSpace = true;
|
bool leadingSpace = true;
|
||||||
|
@ -1484,7 +1463,7 @@ struct ScalarWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Write text as literal block scalar.
|
///Write text as literal block scalar.
|
||||||
void writeLiteral() @system
|
void writeLiteral() @safe
|
||||||
{
|
{
|
||||||
initBlock('|');
|
initBlock('|');
|
||||||
breaks_ = true;
|
breaks_ = true;
|
||||||
|
@ -1511,7 +1490,7 @@ struct ScalarWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Write text as plain scalar.
|
///Write text as plain scalar.
|
||||||
void writePlain() @system
|
void writePlain() @safe
|
||||||
{
|
{
|
||||||
if(emitter_.context_ == Emitter.Context.Root){emitter_.openEnded_ = true;}
|
if(emitter_.context_ == Emitter.Context.Root){emitter_.openEnded_ = true;}
|
||||||
if(text_ == ""){return;}
|
if(text_ == ""){return;}
|
||||||
|
@ -1588,7 +1567,7 @@ struct ScalarWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Determine hints (indicators) for block scalar.
|
///Determine hints (indicators) for block scalar.
|
||||||
size_t determineBlockHints(char[] hints, uint bestIndent) const pure @trusted
|
size_t determineBlockHints(char[] hints, uint bestIndent) const pure @safe
|
||||||
{
|
{
|
||||||
size_t hintsIdx = 0;
|
size_t hintsIdx = 0;
|
||||||
if(text_.length == 0){return hintsIdx;}
|
if(text_.length == 0){return hintsIdx;}
|
||||||
|
@ -1619,12 +1598,12 @@ struct ScalarWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Initialize for block scalar writing with specified indicator.
|
///Initialize for block scalar writing with specified indicator.
|
||||||
void initBlock(const char indicator) @system
|
void initBlock(const char indicator) @safe
|
||||||
{
|
{
|
||||||
char[4] hints;
|
char[4] hints;
|
||||||
hints[0] = indicator;
|
hints[0] = indicator;
|
||||||
const hintsLength = 1 + determineBlockHints(hints[1 .. $], emitter_.bestIndent_);
|
const hintsLength = 1 + determineBlockHints(hints[1 .. $], emitter_.bestIndent_);
|
||||||
emitter_.writeIndicator(cast(string)hints[0 .. hintsLength], Yes.needWhitespace);
|
emitter_.writeIndicator(hints[0 .. hintsLength], Yes.needWhitespace);
|
||||||
if(hints.length > 0 && hints[$ - 1] == '+')
|
if(hints.length > 0 && hints[$ - 1] == '+')
|
||||||
{
|
{
|
||||||
emitter_.openEnded_ = true;
|
emitter_.openEnded_ = true;
|
||||||
|
@ -1633,7 +1612,7 @@ struct ScalarWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Write out the current text range.
|
///Write out the current text range.
|
||||||
void writeCurrentRange(const Flag!"UpdateColumn" updateColumn) @system
|
void writeCurrentRange(const Flag!"UpdateColumn" updateColumn) @safe
|
||||||
{
|
{
|
||||||
emitter_.writeString(text_[startByte_ .. endByte_]);
|
emitter_.writeString(text_[startByte_ .. endByte_]);
|
||||||
if(updateColumn){emitter_.column_ += endChar_ - startChar_;}
|
if(updateColumn){emitter_.column_ += endChar_ - startChar_;}
|
||||||
|
@ -1641,7 +1620,7 @@ struct ScalarWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Write line breaks in the text range.
|
///Write line breaks in the text range.
|
||||||
void writeLineBreaks() @system
|
void writeLineBreaks() @safe
|
||||||
{
|
{
|
||||||
foreach(const dchar br; text_[startByte_ .. endByte_])
|
foreach(const dchar br; text_[startByte_ .. endByte_])
|
||||||
{
|
{
|
||||||
|
@ -1650,20 +1629,20 @@ struct ScalarWriter
|
||||||
{
|
{
|
||||||
char[4] brString;
|
char[4] brString;
|
||||||
const bytes = encode(brString, br);
|
const bytes = encode(brString, br);
|
||||||
emitter_.writeLineBreak(cast(string)brString[0 .. bytes]);
|
emitter_.writeLineBreak(brString[0 .. bytes]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateRangeStart();
|
updateRangeStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
///Write line break if start of the text range is a newline.
|
///Write line break if start of the text range is a newline.
|
||||||
void writeStartLineBreak() @system
|
void writeStartLineBreak() @safe
|
||||||
{
|
{
|
||||||
if(charAtStart == '\n'){emitter_.writeLineBreak();}
|
if(charAtStart == '\n'){emitter_.writeLineBreak();}
|
||||||
}
|
}
|
||||||
|
|
||||||
///Write indentation, optionally resetting whitespace/indentation flags.
|
///Write indentation, optionally resetting whitespace/indentation flags.
|
||||||
void writeIndent(const Flag!"ResetSpace" resetSpace) @system
|
void writeIndent(const Flag!"ResetSpace" resetSpace) @safe
|
||||||
{
|
{
|
||||||
emitter_.writeIndent();
|
emitter_.writeIndent();
|
||||||
if(resetSpace)
|
if(resetSpace)
|
||||||
|
@ -1680,7 +1659,7 @@ struct ScalarWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
///Update the line breaks_ flag, optionally updating the spaces_ flag.
|
///Update the line breaks_ flag, optionally updating the spaces_ flag.
|
||||||
void updateBreaks(in dchar c, const Flag!"UpdateSpaces" updateSpaces) pure @trusted
|
void updateBreaks(in dchar c, const Flag!"UpdateSpaces" updateSpaces) pure @safe
|
||||||
{
|
{
|
||||||
if(c == dcharNone){return;}
|
if(c == dcharNone){return;}
|
||||||
breaks_ = newlineSearch_.canFind(c);
|
breaks_ = newlineSearch_.canFind(c);
|
||||||
|
|
|
@ -89,10 +89,10 @@ struct Event
|
||||||
CollectionStyle collectionStyle = CollectionStyle.Invalid;
|
CollectionStyle collectionStyle = CollectionStyle.Invalid;
|
||||||
|
|
||||||
///Is this a null (uninitialized) event?
|
///Is this a null (uninitialized) event?
|
||||||
@property bool isNull() const pure @system nothrow {return id == EventID.Invalid;}
|
@property bool isNull() const pure @safe nothrow {return id == EventID.Invalid;}
|
||||||
|
|
||||||
///Get string representation of the token ID.
|
///Get string representation of the token ID.
|
||||||
@property string idString() const @system {return to!string(id);}
|
@property string idString() const @safe {return to!string(id);}
|
||||||
|
|
||||||
static assert(Event.sizeof <= 64, "Event struct larger than expected");
|
static assert(Event.sizeof <= 64, "Event struct larger than expected");
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ struct Event
|
||||||
* anchor = Anchor, if this is an alias event.
|
* anchor = Anchor, if this is an alias event.
|
||||||
*/
|
*/
|
||||||
Event event(EventID id)(const Mark start, const Mark end, const string anchor = null)
|
Event event(EventID id)(const Mark start, const Mark end, const string anchor = null)
|
||||||
pure @trusted nothrow
|
@trusted
|
||||||
{
|
{
|
||||||
Event result;
|
Event result;
|
||||||
result.startMark = start;
|
result.startMark = start;
|
||||||
|
@ -149,7 +149,7 @@ Event collectionStartEvent(EventID id)
|
||||||
* encoding = Encoding of the stream.
|
* encoding = Encoding of the stream.
|
||||||
*/
|
*/
|
||||||
Event streamStartEvent(const Mark start, const Mark end, const Encoding encoding)
|
Event streamStartEvent(const Mark start, const Mark end, const Encoding encoding)
|
||||||
pure @trusted nothrow
|
pure @safe nothrow
|
||||||
{
|
{
|
||||||
Event result;
|
Event result;
|
||||||
result.startMark = start;
|
result.startMark = start;
|
||||||
|
@ -198,7 +198,7 @@ Event documentStartEvent(const Mark start, const Mark end, const bool explicit,
|
||||||
* end = End position of the event in the file/stream.
|
* end = End position of the event in the file/stream.
|
||||||
* explicit = Is this an explicit document end?
|
* explicit = Is this an explicit document end?
|
||||||
*/
|
*/
|
||||||
Event documentEndEvent(const Mark start, const Mark end, const bool explicit) pure @trusted nothrow
|
Event documentEndEvent(const Mark start, const Mark end, const bool explicit) pure @safe nothrow
|
||||||
{
|
{
|
||||||
Event result;
|
Event result;
|
||||||
result.startMark = start;
|
result.startMark = start;
|
||||||
|
@ -219,17 +219,15 @@ Event documentEndEvent(const Mark start, const Mark end, const bool explicit) pu
|
||||||
/// style = Scalar style.
|
/// style = Scalar style.
|
||||||
Event scalarEvent(const Mark start, const Mark end, const string anchor, const string tag,
|
Event scalarEvent(const Mark start, const Mark end, const string anchor, const string tag,
|
||||||
const Tuple!(bool, bool) implicit, const string value,
|
const Tuple!(bool, bool) implicit, const string value,
|
||||||
const ScalarStyle style = ScalarStyle.Invalid) @safe pure nothrow @nogc
|
const ScalarStyle style = ScalarStyle.Invalid) @trusted pure nothrow @nogc
|
||||||
{
|
{
|
||||||
Event result;
|
Event result;
|
||||||
result.value = value;
|
result.value = value;
|
||||||
result.startMark = start;
|
result.startMark = start;
|
||||||
result.endMark = end;
|
result.endMark = end;
|
||||||
|
|
||||||
() @trusted {
|
result.anchor = anchor;
|
||||||
result.anchor = anchor;
|
result.tag = tag;
|
||||||
result.tag = tag;
|
|
||||||
}();
|
|
||||||
|
|
||||||
result.id = EventID.Scalar;
|
result.id = EventID.Scalar;
|
||||||
result.scalarStyle = style;
|
result.scalarStyle = style;
|
||||||
|
|
|
@ -35,7 +35,7 @@ template FastCharSearch(dstring chars, uint tableSize = 256)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate the search table and the canFind method.
|
/// Generate the search table and the canFind method.
|
||||||
string searchCode(dstring chars, uint tableSize)() @safe pure //nothrow
|
string searchCode(dstring chars, uint tableSize)()
|
||||||
{
|
{
|
||||||
import std.string;
|
import std.string;
|
||||||
|
|
||||||
|
@ -87,3 +87,9 @@ string searchCode(dstring chars, uint tableSize)() @safe pure //nothrow
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@safe unittest
|
||||||
|
{
|
||||||
|
mixin FastCharSearch!("+", 128) search;
|
||||||
|
assert(search.canFind('+'));
|
||||||
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ struct Flags(names ...) if(names.length <= 8)
|
||||||
///Flag accessors.
|
///Flag accessors.
|
||||||
mixin(flags(names));
|
mixin(flags(names));
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
writeln("Flags unittest");
|
writeln("Flags unittest");
|
||||||
|
|
|
@ -39,7 +39,7 @@ ScalarStyle scalarStyleHack(ref const(Node) node) @safe nothrow
|
||||||
assert(node.isScalar, "Trying to get scalar style of a non-scalar node");
|
assert(node.isScalar, "Trying to get scalar style of a non-scalar node");
|
||||||
return node.scalarStyle;
|
return node.scalarStyle;
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML scalarStyleHack getter unittest");
|
writeln("D:YAML scalarStyleHack getter unittest");
|
||||||
auto node = Node(5);
|
auto node = Node(5);
|
||||||
|
@ -57,7 +57,7 @@ CollectionStyle collectionStyleHack(ref const(Node) node) @safe nothrow
|
||||||
assert(!node.isScalar, "Trying to get collection style of a scalar node");
|
assert(!node.isScalar, "Trying to get collection style of a scalar node");
|
||||||
return node.collectionStyle;
|
return node.collectionStyle;
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML collectionStyleHack getter unittest");
|
writeln("D:YAML collectionStyleHack getter unittest");
|
||||||
auto node = Node([1, 2, 3, 4, 5]);
|
auto node = Node([1, 2, 3, 4, 5]);
|
||||||
|
@ -77,7 +77,7 @@ void scalarStyleHack(ref Node node, const ScalarStyle rhs) @safe nothrow
|
||||||
node.scalarStyle = rhs;
|
node.scalarStyle = rhs;
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML scalarStyleHack setter unittest");
|
writeln("D:YAML scalarStyleHack setter unittest");
|
||||||
auto node = Node(5);
|
auto node = Node(5);
|
||||||
|
@ -97,7 +97,7 @@ void collectionStyleHack(ref Node node, const CollectionStyle rhs) @safe nothrow
|
||||||
node.collectionStyle = rhs;
|
node.collectionStyle = rhs;
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML collectionStyleHack setter unittest");
|
writeln("D:YAML collectionStyleHack setter unittest");
|
||||||
auto node = Node([1, 2, 3, 4, 5]);
|
auto node = Node([1, 2, 3, 4, 5]);
|
||||||
|
|
|
@ -157,9 +157,9 @@ struct Loader
|
||||||
return Loader(cast(ubyte[])data);
|
return Loader(cast(ubyte[])data);
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
assert(Loader.fromString(cast(char[])"42").load().as!int == 42);
|
assert(Loader.fromString("42".dup).load().as!int == 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Construct a Loader to load YAML from a buffer.
|
/** Construct a Loader to load YAML from a buffer.
|
||||||
|
@ -265,12 +265,11 @@ struct Loader
|
||||||
*
|
*
|
||||||
* Throws: YAMLException on a parsing error.
|
* Throws: YAMLException on a parsing error.
|
||||||
*/
|
*/
|
||||||
Node[] loadAll() @trusted
|
Node[] loadAll() @safe
|
||||||
{
|
{
|
||||||
Node[] nodes;
|
Node[] nodes;
|
||||||
foreach(ref node; this)
|
foreach(ref node; this)
|
||||||
{
|
{
|
||||||
nodes.assumeSafeAppend();
|
|
||||||
nodes ~= node;
|
nodes ~= node;
|
||||||
}
|
}
|
||||||
return nodes;
|
return nodes;
|
||||||
|
@ -316,14 +315,13 @@ struct Loader
|
||||||
|
|
||||||
package:
|
package:
|
||||||
// Scan and return all tokens. Used for debugging.
|
// Scan and return all tokens. Used for debugging.
|
||||||
Token[] scan() @trusted
|
Token[] scan() @safe
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Token[] result;
|
Token[] result;
|
||||||
while(scanner_.checkToken())
|
while(scanner_.checkToken())
|
||||||
{
|
{
|
||||||
result.assumeSafeAppend();
|
|
||||||
result ~= scanner_.getToken();
|
result ~= scanner_.getToken();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -378,7 +376,7 @@ struct Loader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
char[] yaml_input = ("red: '#ff0000'\n" ~
|
char[] yaml_input = ("red: '#ff0000'\n" ~
|
||||||
"green: '#00ff00'\n" ~
|
"green: '#00ff00'\n" ~
|
||||||
|
|
|
@ -112,7 +112,7 @@ package class YAMLContainer(T) if (!Node.allowed!T): YAMLObject
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Construct a YAMLContainer holding specified value.
|
// Construct a YAMLContainer holding specified value.
|
||||||
this(T value) @trusted {value_ = value;}
|
this(T value) @safe {value_ = value;}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ private struct Pair
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Construct a Pair from two values. Will be converted to Nodes if needed.
|
/// Construct a Pair from two values. Will be converted to Nodes if needed.
|
||||||
this(K, V)(K key, V value) @safe
|
this(K, V)(K key, V value)
|
||||||
{
|
{
|
||||||
static if(is(Unqual!K == Node)){this.key = key;}
|
static if(is(Unqual!K == Node)){this.key = key;}
|
||||||
else {this.key = Node(key);}
|
else {this.key = Node(key);}
|
||||||
|
@ -265,7 +265,7 @@ struct Node
|
||||||
}
|
}
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
// Overload for types where we can make this nothrow.
|
// Overload for types where we can make this nothrow.
|
||||||
this(T)(T value, const string tag = null) @trusted pure nothrow
|
this(T)(T value, const string tag = null) @trusted
|
||||||
if(scalarCtorNothrow!T)
|
if(scalarCtorNothrow!T)
|
||||||
{
|
{
|
||||||
tag_ = tag;
|
tag_ = tag;
|
||||||
|
@ -276,7 +276,7 @@ struct Node
|
||||||
// User defined type or plain string.
|
// User defined type or plain string.
|
||||||
else { value_ = Value(value);}
|
else { value_ = Value(value);}
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
auto node = Node(42);
|
auto node = Node(42);
|
||||||
|
@ -343,7 +343,7 @@ struct Node
|
||||||
value_ = Value(nodes);
|
value_ = Value(nodes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
with(Node([1, 2, 3]))
|
with(Node([1, 2, 3]))
|
||||||
{
|
{
|
||||||
|
@ -393,7 +393,7 @@ struct Node
|
||||||
foreach(key, ref value; array){pairs ~= Pair(key, value);}
|
foreach(key, ref value; array){pairs ~= Pair(key, value);}
|
||||||
value_ = Value(pairs);
|
value_ = Value(pairs);
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
int[string] aa;
|
int[string] aa;
|
||||||
aa["1"] = 1;
|
aa["1"] = 1;
|
||||||
|
@ -465,7 +465,7 @@ struct Node
|
||||||
foreach(i; 0 .. keys.length){pairs ~= Pair(keys[i], values[i]);}
|
foreach(i; 0 .. keys.length){pairs ~= Pair(keys[i], values[i]);}
|
||||||
value_ = Value(pairs);
|
value_ = Value(pairs);
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
with(Node(["1", "2"], [1, 2]))
|
with(Node(["1", "2"], [1, 2]))
|
||||||
{
|
{
|
||||||
|
@ -535,12 +535,12 @@ struct Node
|
||||||
*
|
*
|
||||||
* Returns: true if equal, false otherwise.
|
* Returns: true if equal, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool opEquals(T)(const auto ref T rhs) const @safe
|
bool opEquals(T)(const auto ref T rhs) const
|
||||||
{
|
{
|
||||||
return equals!(Yes.useTag)(rhs);
|
return equals!(Yes.useTag)(rhs);
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
auto node = Node(42);
|
auto node = Node(42);
|
||||||
|
|
||||||
|
@ -671,7 +671,7 @@ struct Node
|
||||||
}
|
}
|
||||||
assert(false, "This code should never be reached");
|
assert(false, "This code should never be reached");
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
assertThrown!NodeException(Node("42").get!int);
|
assertThrown!NodeException(Node("42").get!int);
|
||||||
Node(YAMLNull()).get!YAMLNull;
|
Node(YAMLNull()).get!YAMLNull;
|
||||||
|
@ -807,7 +807,7 @@ struct Node
|
||||||
throw new Error("Trying to index a " ~ nodeTypeString ~ " node", startMark_);
|
throw new Error("Trying to index a " ~ nodeTypeString ~ " node", startMark_);
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Node opIndex unittest");
|
writeln("D:YAML Node opIndex unittest");
|
||||||
alias Node.Value Value;
|
alias Node.Value Value;
|
||||||
|
@ -821,7 +821,7 @@ struct Node
|
||||||
assert(nmap["11"].as!int == 11);
|
assert(nmap["11"].as!int == 11);
|
||||||
assert(nmap["14"].as!int == 14);
|
assert(nmap["14"].as!int == 14);
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Node opIndex unittest");
|
writeln("D:YAML Node opIndex unittest");
|
||||||
alias Node.Value Value;
|
alias Node.Value Value;
|
||||||
|
@ -856,7 +856,7 @@ struct Node
|
||||||
*
|
*
|
||||||
* Throws: NodeException if the node is not a collection.
|
* Throws: NodeException if the node is not a collection.
|
||||||
*/
|
*/
|
||||||
bool contains(T)(T rhs) const @safe
|
bool contains(T)(T rhs) const
|
||||||
{
|
{
|
||||||
return contains_!(T, No.key, "contains")(rhs);
|
return contains_!(T, No.key, "contains")(rhs);
|
||||||
}
|
}
|
||||||
|
@ -870,13 +870,13 @@ struct Node
|
||||||
*
|
*
|
||||||
* Throws: NodeException if the node is not a mapping.
|
* Throws: NodeException if the node is not a mapping.
|
||||||
*/
|
*/
|
||||||
bool containsKey(T)(T rhs) const @safe
|
bool containsKey(T)(T rhs) const
|
||||||
{
|
{
|
||||||
return contains_!(T, Yes.key, "containsKey")(rhs);
|
return contains_!(T, Yes.key, "containsKey")(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unittest for contains() and containsKey().
|
// Unittest for contains() and containsKey().
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Node contains/containsKey unittest");
|
writeln("D:YAML Node contains/containsKey unittest");
|
||||||
auto seq = Node([1, 2, 3, 4, 5]);
|
auto seq = Node([1, 2, 3, 4, 5]);
|
||||||
|
@ -946,7 +946,7 @@ struct Node
|
||||||
collectionStyle = rhs.collectionStyle;
|
collectionStyle = rhs.collectionStyle;
|
||||||
}
|
}
|
||||||
// Unittest for opAssign().
|
// Unittest for opAssign().
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
auto seq = Node([1, 2, 3, 4, 5]);
|
auto seq = Node([1, 2, 3, 4, 5]);
|
||||||
auto assigned = seq;
|
auto assigned = seq;
|
||||||
|
@ -1007,7 +1007,7 @@ struct Node
|
||||||
|
|
||||||
throw new Error("Trying to index a " ~ nodeTypeString ~ " node", startMark_);
|
throw new Error("Trying to index a " ~ nodeTypeString ~ " node", startMark_);
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Node opIndexAssign unittest");
|
writeln("D:YAML Node opIndexAssign unittest");
|
||||||
|
|
||||||
|
@ -1048,7 +1048,7 @@ struct Node
|
||||||
* Throws: NodeException if the node is not a sequence or an element
|
* Throws: NodeException if the node is not a sequence or an element
|
||||||
* could not be converted to specified type.
|
* could not be converted to specified type.
|
||||||
*/
|
*/
|
||||||
auto sequence(T = Node)() @trusted
|
auto sequence(T = Node)()
|
||||||
{
|
{
|
||||||
enforce(isSequence,
|
enforce(isSequence,
|
||||||
new Error("Trying to 'sequence'-iterate over a " ~ nodeTypeString ~ " node",
|
new Error("Trying to 'sequence'-iterate over a " ~ nodeTypeString ~ " node",
|
||||||
|
@ -1118,7 +1118,7 @@ struct Node
|
||||||
}
|
}
|
||||||
return Range(get!(Node[]));
|
return Range(get!(Node[]));
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Node sequence unittest");
|
writeln("D:YAML Node sequence unittest");
|
||||||
|
|
||||||
|
@ -1137,56 +1137,56 @@ struct Node
|
||||||
* Throws: NodeException if the node is not a mapping.
|
* Throws: NodeException if the node is not a mapping.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
auto mapping() @trusted
|
auto mapping() @safe
|
||||||
{
|
{
|
||||||
enforce(isMapping,
|
enforce(isMapping,
|
||||||
new Error("Trying to 'mapping'-iterate over a "
|
new Error("Trying to 'mapping'-iterate over a "
|
||||||
~ nodeTypeString ~ " node", startMark_));
|
~ nodeTypeString ~ " node", startMark_));
|
||||||
struct Range
|
struct Range
|
||||||
{
|
{
|
||||||
Node.Pair[] pairs;
|
Node.Pair[] pairs;
|
||||||
size_t position;
|
size_t position;
|
||||||
|
|
||||||
this(Node.Pair[] pairs)
|
this(Node.Pair[] pairs) @safe
|
||||||
{
|
{
|
||||||
this.pairs = pairs;
|
this.pairs = pairs;
|
||||||
position = 0;
|
position = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Input range functionality. */
|
/* Input range functionality. */
|
||||||
bool empty() { return position >= pairs.length; }
|
bool empty() @safe { return position >= pairs.length; }
|
||||||
|
|
||||||
void popFront()
|
void popFront() @safe
|
||||||
{
|
{
|
||||||
enforce(!empty, "Attempted to popFront an empty mapping");
|
enforce(!empty, "Attempted to popFront an empty mapping");
|
||||||
position++;
|
position++;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pair front()
|
Pair front() @safe
|
||||||
{
|
{
|
||||||
enforce(!empty, "Attempted to take the front of an empty mapping");
|
enforce(!empty, "Attempted to take the front of an empty mapping");
|
||||||
return pairs[position];
|
return pairs[position];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Forward range functionality. */
|
/* Forward range functionality. */
|
||||||
Range save() { return this; }
|
Range save() @safe { return this; }
|
||||||
|
|
||||||
/* Bidirectional range functionality. */
|
/* Bidirectional range functionality. */
|
||||||
void popBack()
|
void popBack() @safe
|
||||||
{
|
{
|
||||||
enforce(!empty, "Attempted to popBack an empty mapping");
|
enforce(!empty, "Attempted to popBack an empty mapping");
|
||||||
pairs = pairs[0 .. $ - 1];
|
pairs = pairs[0 .. $ - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
Pair back()
|
Pair back() @safe
|
||||||
{
|
{
|
||||||
enforce(!empty, "Attempted to take the back of an empty mapping");
|
enforce(!empty, "Attempted to take the back of an empty mapping");
|
||||||
return pairs[$ - 1];
|
return pairs[$ - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Random-access range functionality. */
|
/* Random-access range functionality. */
|
||||||
size_t length() const @property { return pairs.length; }
|
size_t length() const @property @safe { return pairs.length; }
|
||||||
Pair opIndex(size_t index) { return pairs[index]; }
|
Pair opIndex(size_t index) @safe { return pairs[index]; }
|
||||||
|
|
||||||
static assert(isInputRange!Range);
|
static assert(isInputRange!Range);
|
||||||
static assert(isForwardRange!Range);
|
static assert(isForwardRange!Range);
|
||||||
|
@ -1195,7 +1195,7 @@ struct Node
|
||||||
}
|
}
|
||||||
return Range(get!(Node.Pair[]));
|
return Range(get!(Node.Pair[]));
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Node mapping unittest");
|
writeln("D:YAML Node mapping unittest");
|
||||||
|
|
||||||
|
@ -1222,7 +1222,7 @@ struct Node
|
||||||
* Throws: NodeException if the nodes is not a mapping or an element
|
* Throws: NodeException if the nodes is not a mapping or an element
|
||||||
* could not be converted to specified type.
|
* could not be converted to specified type.
|
||||||
*/
|
*/
|
||||||
auto mappingKeys(K = Node)() @trusted
|
auto mappingKeys(K = Node)()
|
||||||
{
|
{
|
||||||
enforce(isMapping,
|
enforce(isMapping,
|
||||||
new Error("Trying to 'mappingKeys'-iterate over a "
|
new Error("Trying to 'mappingKeys'-iterate over a "
|
||||||
|
@ -1232,7 +1232,7 @@ struct Node
|
||||||
else
|
else
|
||||||
return mapping.map!(pair => pair.key.as!K);
|
return mapping.map!(pair => pair.key.as!K);
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Node mappingKeys unittest");
|
writeln("D:YAML Node mappingKeys unittest");
|
||||||
|
|
||||||
|
@ -1252,7 +1252,7 @@ struct Node
|
||||||
* Throws: NodeException if the nodes is not a mapping or an element
|
* Throws: NodeException if the nodes is not a mapping or an element
|
||||||
* could not be converted to specified type.
|
* could not be converted to specified type.
|
||||||
*/
|
*/
|
||||||
auto mappingValues(V = Node)() @trusted
|
auto mappingValues(V = Node)()
|
||||||
{
|
{
|
||||||
enforce(isMapping,
|
enforce(isMapping,
|
||||||
new Error("Trying to 'mappingValues'-iterate over a "
|
new Error("Trying to 'mappingValues'-iterate over a "
|
||||||
|
@ -1262,7 +1262,7 @@ struct Node
|
||||||
else
|
else
|
||||||
return mapping.map!(pair => pair.value.as!V);
|
return mapping.map!(pair => pair.value.as!V);
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Node mappingValues unittest");
|
writeln("D:YAML Node mappingValues unittest");
|
||||||
|
|
||||||
|
@ -1304,7 +1304,7 @@ struct Node
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
unittest
|
@system unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Node opApply unittest 1");
|
writeln("D:YAML Node opApply unittest 1");
|
||||||
|
|
||||||
|
@ -1372,7 +1372,7 @@ struct Node
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Node opApply unittest 2");
|
writeln("D:YAML Node opApply unittest 2");
|
||||||
|
|
||||||
|
@ -1447,7 +1447,7 @@ struct Node
|
||||||
else {nodes ~= Node(value);}
|
else {nodes ~= Node(value);}
|
||||||
value_ = Value(nodes);
|
value_ = Value(nodes);
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Node add unittest 1");
|
writeln("D:YAML Node add unittest 1");
|
||||||
|
|
||||||
|
@ -1484,7 +1484,7 @@ struct Node
|
||||||
pairs ~= Pair(key, value);
|
pairs ~= Pair(key, value);
|
||||||
value_ = Value(pairs);
|
value_ = Value(pairs);
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Node add unittest 2");
|
writeln("D:YAML Node add unittest 2");
|
||||||
with(Node([1, 2], [3, 4]))
|
with(Node([1, 2], [3, 4]))
|
||||||
|
@ -1508,7 +1508,7 @@ struct Node
|
||||||
*
|
*
|
||||||
* See_Also: contains
|
* See_Also: contains
|
||||||
*/
|
*/
|
||||||
Node* opBinaryRight(string op, K)(K key) @system
|
Node* opBinaryRight(string op, K)(K key)
|
||||||
if (op == "in")
|
if (op == "in")
|
||||||
{
|
{
|
||||||
enforce(isMapping, new Error("Trying to use 'in' on a " ~
|
enforce(isMapping, new Error("Trying to use 'in' on a " ~
|
||||||
|
@ -1524,7 +1524,7 @@ struct Node
|
||||||
return &(get!(Node.Pair[])[idx].value);
|
return &(get!(Node.Pair[])[idx].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln(`D:YAML Node opBinaryRight!"in" unittest`);
|
writeln(`D:YAML Node opBinaryRight!"in" unittest`);
|
||||||
auto mapping = Node(["foo", "baz"], ["bar", "qux"]);
|
auto mapping = Node(["foo", "baz"], ["bar", "qux"]);
|
||||||
|
@ -1553,7 +1553,7 @@ struct Node
|
||||||
{
|
{
|
||||||
remove_!(T, No.key, "remove")(rhs);
|
remove_!(T, No.key, "remove")(rhs);
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Node remove unittest");
|
writeln("D:YAML Node remove unittest");
|
||||||
with(Node([1, 2, 3, 4, 3]))
|
with(Node([1, 2, 3, 4, 3]))
|
||||||
|
@ -1601,7 +1601,7 @@ struct Node
|
||||||
{
|
{
|
||||||
remove_!(T, Yes.key, "removeAt")(index);
|
remove_!(T, Yes.key, "removeAt")(index);
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Node removeAt unittest");
|
writeln("D:YAML Node removeAt unittest");
|
||||||
with(Node([1, 2, 3, 4, 3]))
|
with(Node([1, 2, 3, 4, 3]))
|
||||||
|
@ -1632,13 +1632,13 @@ struct Node
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute hash of the node.
|
// Compute hash of the node.
|
||||||
hash_t toHash() nothrow const
|
hash_t toHash() nothrow const @trusted
|
||||||
{
|
{
|
||||||
const tagHash = (tag_ is null) ? 0 : tag_.hashOf();
|
const valueHash = value_.toHash();
|
||||||
// Variant toHash is not const at the moment, so we need to const-cast.
|
|
||||||
return tagHash + value_.toHash();
|
return tag_ is null ? valueHash : tag_.hashOf(valueHash);
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("Node(42).toHash(): ", Node(42).toHash());
|
writeln("Node(42).toHash(): ", Node(42).toHash());
|
||||||
}
|
}
|
||||||
|
@ -1668,13 +1668,13 @@ struct Node
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct Node.Value from user defined type.
|
// Construct Node.Value from user defined type.
|
||||||
static Value userValue(T)(T value) @trusted nothrow
|
static Value userValue(T)(T value) @trusted
|
||||||
{
|
{
|
||||||
return Value(cast(YAMLObject)new YAMLContainer!T(value));
|
return Value(cast(YAMLObject)new YAMLContainer!T(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct Node.Value from a type it can store directly (after casting if needed)
|
// Construct Node.Value from a type it can store directly (after casting if needed)
|
||||||
static Value value(T)(T value) @system nothrow if(allowed!T)
|
static Value value(T)(T value) if(allowed!T)
|
||||||
{
|
{
|
||||||
static if(Value.allowed!T)
|
static if(Value.allowed!T)
|
||||||
{
|
{
|
||||||
|
@ -1702,7 +1702,7 @@ struct Node
|
||||||
// Equality test with any value.
|
// Equality test with any value.
|
||||||
//
|
//
|
||||||
// useTag determines whether or not to consider tags in node-node comparisons.
|
// useTag determines whether or not to consider tags in node-node comparisons.
|
||||||
bool equals(Flag!"useTag" useTag, T)(ref T rhs) const @safe
|
bool equals(Flag!"useTag" useTag, T)(ref T rhs) const
|
||||||
{
|
{
|
||||||
static if(is(Unqual!T == Node))
|
static if(is(Unqual!T == Node))
|
||||||
{
|
{
|
||||||
|
@ -1843,7 +1843,7 @@ struct Node
|
||||||
// Params: level = Level of the node in the tree.
|
// Params: level = Level of the node in the tree.
|
||||||
//
|
//
|
||||||
// Returns: String representing the node tree.
|
// Returns: String representing the node tree.
|
||||||
@property string debugString(uint level = 0) @trusted
|
@property string debugString(uint level = 0) @safe
|
||||||
{
|
{
|
||||||
string indent;
|
string indent;
|
||||||
foreach(i; 0 .. level){indent ~= " ";}
|
foreach(i; 0 .. level){indent ~= " ";}
|
||||||
|
@ -1879,17 +1879,16 @@ struct Node
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get type of the node value (YAMLObject for user types).
|
// Get type of the node value (YAMLObject for user types).
|
||||||
@property TypeInfo type() const @trusted nothrow
|
@property TypeInfo type() const @safe nothrow
|
||||||
{
|
{
|
||||||
alias TypeInfo delegate() const nothrow nothrowType;
|
return value_.type;
|
||||||
return (cast(nothrowType)&value_.type)();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Determine if the value stored by the node is of specified type.
|
// Determine if the value stored by the node is of specified type.
|
||||||
//
|
//
|
||||||
// This only works for default YAML types, not for user defined types.
|
// This only works for default YAML types, not for user defined types.
|
||||||
@property bool isType(T)() const @safe nothrow
|
@property bool isType(T)() const
|
||||||
{
|
{
|
||||||
return this.type is typeid(Unqual!T);
|
return this.type is typeid(Unqual!T);
|
||||||
}
|
}
|
||||||
|
@ -1928,7 +1927,7 @@ struct Node
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine if the value can be converted to specified type.
|
// Determine if the value can be converted to specified type.
|
||||||
@property bool convertsTo(T)() const @safe nothrow
|
@property bool convertsTo(T)() const
|
||||||
{
|
{
|
||||||
if(isType!T){return true;}
|
if(isType!T){return true;}
|
||||||
|
|
||||||
|
@ -1963,7 +1962,7 @@ struct Node
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation of remove() and removeAt()
|
// Implementation of remove() and removeAt()
|
||||||
void remove_(T, Flag!"key" key, string func)(T rhs) @system
|
void remove_(T, Flag!"key" key, string func)(T rhs)
|
||||||
{
|
{
|
||||||
enforce(isSequence || isMapping,
|
enforce(isSequence || isMapping,
|
||||||
new Error("Trying to " ~ func ~ "() from a " ~ nodeTypeString ~ " node",
|
new Error("Trying to " ~ func ~ "() from a " ~ nodeTypeString ~ " node",
|
||||||
|
@ -2083,7 +2082,7 @@ package:
|
||||||
//
|
//
|
||||||
// Params: pairs = Appender managing the array of pairs to merge into.
|
// Params: pairs = Appender managing the array of pairs to merge into.
|
||||||
// toMerge = Pair to merge.
|
// toMerge = Pair to merge.
|
||||||
void merge(ref Appender!(Node.Pair[]) pairs, ref Node.Pair toMerge) @trusted
|
void merge(ref Appender!(Node.Pair[]) pairs, ref Node.Pair toMerge) @safe
|
||||||
{
|
{
|
||||||
foreach(ref pair; pairs.data)
|
foreach(ref pair; pairs.data)
|
||||||
{
|
{
|
||||||
|
@ -2099,7 +2098,7 @@ void merge(ref Appender!(Node.Pair[]) pairs, ref Node.Pair toMerge) @trusted
|
||||||
//
|
//
|
||||||
// Params: pairs = Appender managing the array of pairs to merge into.
|
// Params: pairs = Appender managing the array of pairs to merge into.
|
||||||
// toMerge = Pairs to merge.
|
// toMerge = Pairs to merge.
|
||||||
void merge(ref Appender!(Node.Pair[]) pairs, Node.Pair[] toMerge) @trusted
|
void merge(ref Appender!(Node.Pair[]) pairs, Node.Pair[] toMerge) @safe
|
||||||
{
|
{
|
||||||
bool eq(ref Node.Pair a, ref Node.Pair b){return a.key == b.key;}
|
bool eq(ref Node.Pair a, ref Node.Pair b){return a.key == b.key;}
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ struct AppenderNoGCFixed(A : T[], T)
|
||||||
/// Construct an appender that will work with given buffer.
|
/// Construct an appender that will work with given buffer.
|
||||||
///
|
///
|
||||||
/// Data written to the appender will overwrite the buffer from the start.
|
/// Data written to the appender will overwrite the buffer from the start.
|
||||||
this(T[] arr) @trusted pure nothrow
|
this(T[] arr) @safe pure nothrow
|
||||||
{
|
{
|
||||||
// initialize to a given array.
|
// initialize to a given array.
|
||||||
_data.arr = cast(Unqual!T[])arr[0 .. 0]; //trusted
|
_data.arr = cast(Unqual!T[])arr[0 .. 0]; //trusted
|
||||||
|
@ -163,11 +163,8 @@ struct AppenderNoGCFixed(A : T[], T)
|
||||||
/**
|
/**
|
||||||
* Returns the managed array.
|
* Returns the managed array.
|
||||||
*/
|
*/
|
||||||
@property inout(T)[] data() inout @trusted pure nothrow
|
@property inout(T)[] data() inout @safe pure nothrow
|
||||||
{
|
{
|
||||||
/* @trusted operation:
|
|
||||||
* casting Unqual!T[] to inout(T)[]
|
|
||||||
*/
|
|
||||||
return cast(typeof(return))(_data.arr);
|
return cast(typeof(return))(_data.arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +214,7 @@ struct AppenderNoGCFixed(A : T[], T)
|
||||||
@disable void clear();
|
@disable void clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
char[256] buffer;
|
char[256] buffer;
|
||||||
auto appender = appenderNoGC(buffer[]);
|
auto appender = appenderNoGC(buffer[]);
|
||||||
|
@ -245,7 +242,7 @@ struct ValidateResult
|
||||||
/// Validate a UTF-8 string, checking if it is well-formed Unicode.
|
/// Validate a UTF-8 string, checking if it is well-formed Unicode.
|
||||||
///
|
///
|
||||||
/// See_Also: ValidateResult
|
/// See_Also: ValidateResult
|
||||||
ValidateResult validateUTF8NoGC(const(char[]) str) @trusted pure nothrow @nogc
|
ValidateResult validateUTF8NoGC(const(char[]) str) @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
immutable len = str.length;
|
immutable len = str.length;
|
||||||
size_t characterCount;
|
size_t characterCount;
|
||||||
|
@ -289,7 +286,6 @@ ValidateResult validateUTF8NoGC(const(char[]) str) @trusted pure nothrow @nogc
|
||||||
/// 'string errorMessage' member that is null on success and otherwise stores
|
/// 'string errorMessage' member that is null on success and otherwise stores
|
||||||
/// the error message.
|
/// the error message.
|
||||||
auto decodeUTF8NoGC(Flag!"validated" validated)(const(char[]) str, ref size_t index)
|
auto decodeUTF8NoGC(Flag!"validated" validated)(const(char[]) str, ref size_t index)
|
||||||
@trusted pure nothrow @nogc
|
|
||||||
{
|
{
|
||||||
static if(!validated) struct Result
|
static if(!validated) struct Result
|
||||||
{
|
{
|
||||||
|
@ -301,7 +297,7 @@ auto decodeUTF8NoGC(Flag!"validated" validated)(const(char[]) str, ref size_t in
|
||||||
/// Dchar bitmask for different numbers of UTF-8 code units.
|
/// Dchar bitmask for different numbers of UTF-8 code units.
|
||||||
enum bitMask = tuple((1 << 7) - 1, (1 << 11) - 1, (1 << 16) - 1, (1 << 21) - 1);
|
enum bitMask = tuple((1 << 7) - 1, (1 << 11) - 1, (1 << 16) - 1, (1 << 21) - 1);
|
||||||
|
|
||||||
auto pstr = str.ptr + index;
|
auto pstr = str[index..$];
|
||||||
|
|
||||||
immutable length = str.length - index;
|
immutable length = str.length - index;
|
||||||
ubyte fst = pstr[0];
|
ubyte fst = pstr[0];
|
||||||
|
|
|
@ -127,12 +127,12 @@ final class Parser
|
||||||
TagDirective[] tagDirectives_;
|
TagDirective[] tagDirectives_;
|
||||||
|
|
||||||
///Stack of states.
|
///Stack of states.
|
||||||
Array!(Event delegate()) states_;
|
Array!(Event delegate() @safe) states_;
|
||||||
///Stack of marks used to keep track of extents of e.g. YAML collections.
|
///Stack of marks used to keep track of extents of e.g. YAML collections.
|
||||||
Array!Mark marks_;
|
Array!Mark marks_;
|
||||||
|
|
||||||
///Current state.
|
///Current state.
|
||||||
Event delegate() state_;
|
Event delegate() @safe state_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
///Construct a Parser using specified Scanner.
|
///Construct a Parser using specified Scanner.
|
||||||
|
@ -165,7 +165,7 @@ final class Parser
|
||||||
* or if there are any events left if no types specified.
|
* or if there are any events left if no types specified.
|
||||||
* false otherwise.
|
* false otherwise.
|
||||||
*/
|
*/
|
||||||
bool checkEvent(EventID[] ids...) @trusted
|
bool checkEvent(EventID[] ids...) @safe
|
||||||
{
|
{
|
||||||
//Check if the next event is one of specified types.
|
//Check if the next event is one of specified types.
|
||||||
if(currentEvent_.isNull && state_ !is null)
|
if(currentEvent_.isNull && state_ !is null)
|
||||||
|
@ -228,7 +228,7 @@ final class Parser
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///Pop and return the newest state in states_.
|
///Pop and return the newest state in states_.
|
||||||
Event delegate() popState() @trusted
|
Event delegate() @safe popState() @trusted
|
||||||
{
|
{
|
||||||
enforce(states_.length > 0,
|
enforce(states_.length > 0,
|
||||||
new YAMLException("Parser: Need to pop state but no states left to pop"));
|
new YAMLException("Parser: Need to pop state but no states left to pop"));
|
||||||
|
@ -347,7 +347,7 @@ final class Parser
|
||||||
while(scanner_.checkToken(TokenID.Directive))
|
while(scanner_.checkToken(TokenID.Directive))
|
||||||
{
|
{
|
||||||
const token = scanner_.getToken();
|
const token = scanner_.getToken();
|
||||||
const value = token.value;
|
string value = token.value.idup;
|
||||||
if(token.directive == DirectiveType.YAML)
|
if(token.directive == DirectiveType.YAML)
|
||||||
{
|
{
|
||||||
enforce(YAMLVersion_ is null,
|
enforce(YAMLVersion_ is null,
|
||||||
|
@ -356,11 +356,11 @@ final class Parser
|
||||||
enforce(minor == "1",
|
enforce(minor == "1",
|
||||||
new Error("Incompatible document (version 1.x is required)",
|
new Error("Incompatible document (version 1.x is required)",
|
||||||
token.startMark));
|
token.startMark));
|
||||||
YAMLVersion_ = cast(string)value;
|
YAMLVersion_ = value;
|
||||||
}
|
}
|
||||||
else if(token.directive == DirectiveType.TAG)
|
else if(token.directive == DirectiveType.TAG)
|
||||||
{
|
{
|
||||||
auto handle = cast(string)value[0 .. token.valueDivider];
|
auto handle = value[0 .. token.valueDivider];
|
||||||
|
|
||||||
foreach(ref pair; tagDirectives_)
|
foreach(ref pair; tagDirectives_)
|
||||||
{
|
{
|
||||||
|
@ -369,8 +369,8 @@ final class Parser
|
||||||
enforce(h != handle, new Error("Duplicate tag handle: " ~ handle,
|
enforce(h != handle, new Error("Duplicate tag handle: " ~ handle,
|
||||||
token.startMark));
|
token.startMark));
|
||||||
}
|
}
|
||||||
tagDirectives_ ~=
|
tagDirectives_ ~=
|
||||||
TagDirective(handle, cast(string)value[token.valueDivider .. $]);
|
TagDirective(handle, value[token.valueDivider .. $]);
|
||||||
}
|
}
|
||||||
// Any other directive type is ignored (only YAML and TAG are in YAML
|
// Any other directive type is ignored (only YAML and TAG are in YAML
|
||||||
// 1.1/1.2, any other directives are "reserved")
|
// 1.1/1.2, any other directives are "reserved")
|
||||||
|
@ -432,7 +432,7 @@ final class Parser
|
||||||
uint tagHandleEnd;
|
uint tagHandleEnd;
|
||||||
|
|
||||||
//Get anchor/tag if detected. Return false otherwise.
|
//Get anchor/tag if detected. Return false otherwise.
|
||||||
bool get(const TokenID id, const Flag!"first" first, ref string target)
|
bool get(const TokenID id, const Flag!"first" first, ref string target) @trusted
|
||||||
{
|
{
|
||||||
if(!scanner_.checkToken(id)){return false;}
|
if(!scanner_.checkToken(id)){return false;}
|
||||||
invalidMarks = false;
|
invalidMarks = false;
|
||||||
|
@ -536,7 +536,7 @@ final class Parser
|
||||||
/// Handle escape sequences in a double quoted scalar.
|
/// Handle escape sequences in a double quoted scalar.
|
||||||
///
|
///
|
||||||
/// Moved here from scanner as it can't always be done in-place with slices.
|
/// Moved here from scanner as it can't always be done in-place with slices.
|
||||||
string handleDoubleQuotedScalarEscapes(char[] tokenValue)
|
string handleDoubleQuotedScalarEscapes(char[] tokenValue) const @system
|
||||||
{
|
{
|
||||||
string notInPlace;
|
string notInPlace;
|
||||||
bool inEscape = false;
|
bool inEscape = false;
|
||||||
|
@ -623,7 +623,7 @@ final class Parser
|
||||||
*/
|
*/
|
||||||
string processTag(const string tag, const uint handleEnd,
|
string processTag(const string tag, const uint handleEnd,
|
||||||
const Mark startMark, const Mark tagMark)
|
const Mark startMark, const Mark tagMark)
|
||||||
const @trusted
|
const @safe
|
||||||
{
|
{
|
||||||
const handle = tag[0 .. handleEnd];
|
const handle = tag[0 .. handleEnd];
|
||||||
const suffix = tag[handleEnd .. $];
|
const suffix = tag[handleEnd .. $];
|
||||||
|
@ -829,7 +829,7 @@ final class Parser
|
||||||
}
|
}
|
||||||
|
|
||||||
///Parse a key in flow context.
|
///Parse a key in flow context.
|
||||||
Event parseFlowKey(in Event delegate() nextState) @trusted
|
Event parseFlowKey(in Event delegate() @safe nextState) @trusted
|
||||||
{
|
{
|
||||||
const token = scanner_.getToken();
|
const token = scanner_.getToken();
|
||||||
|
|
||||||
|
@ -851,7 +851,7 @@ final class Parser
|
||||||
}
|
}
|
||||||
|
|
||||||
///Parse a mapping value in a flow context.
|
///Parse a mapping value in a flow context.
|
||||||
Event parseFlowValue(TokenID checkId, in Event delegate() nextState)
|
Event parseFlowValue(TokenID checkId, in Event delegate() @safe nextState)
|
||||||
@trusted
|
@trusted
|
||||||
{
|
{
|
||||||
if(scanner_.checkToken(TokenID.Value))
|
if(scanner_.checkToken(TokenID.Value))
|
||||||
|
|
|
@ -220,7 +220,7 @@ void free(T)(T* ptr) @system nothrow
|
||||||
core.stdc.stdlib.free(ptr);
|
core.stdc.stdlib.free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
auto queue = Queue!int();
|
auto queue = Queue!int();
|
||||||
assert(queue.empty);
|
assert(queue.empty);
|
||||||
|
|
|
@ -94,7 +94,7 @@ final class Reader
|
||||||
///
|
///
|
||||||
/// Throws: ReaderException on a UTF decoding error or if there are
|
/// Throws: ReaderException on a UTF decoding error or if there are
|
||||||
/// nonprintable Unicode characters illegal in YAML.
|
/// nonprintable Unicode characters illegal in YAML.
|
||||||
this(ubyte[] buffer) @trusted pure //!nothrow
|
this(ubyte[] buffer) @trusted pure
|
||||||
{
|
{
|
||||||
auto endianResult = fixUTFByteOrder(buffer);
|
auto endianResult = fixUTFByteOrder(buffer);
|
||||||
if(endianResult.bytesStripped > 0)
|
if(endianResult.bytesStripped > 0)
|
||||||
|
@ -124,7 +124,6 @@ final class Reader
|
||||||
checkASCII();
|
checkASCII();
|
||||||
}
|
}
|
||||||
|
|
||||||
pure nothrow @nogc:
|
|
||||||
/// Get character at specified index relative to current position.
|
/// Get character at specified index relative to current position.
|
||||||
///
|
///
|
||||||
/// Params: index = Index of the character to get relative to current position
|
/// Params: index = Index of the character to get relative to current position
|
||||||
|
@ -135,7 +134,7 @@ pure nothrow @nogc:
|
||||||
///
|
///
|
||||||
// XXX removed; search for 'risky' to find why.
|
// XXX removed; search for 'risky' to find why.
|
||||||
// Throws: ReaderException if trying to read past the end of the buffer.
|
// Throws: ReaderException if trying to read past the end of the buffer.
|
||||||
dchar peek(const size_t index) @safe
|
dchar peek(const size_t index) @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
if(index < upcomingASCII_) { return buffer_[bufferOffset_ + index]; }
|
if(index < upcomingASCII_) { return buffer_[bufferOffset_ + index]; }
|
||||||
if(characterCount_ <= charIndex_ + index)
|
if(characterCount_ <= charIndex_ + index)
|
||||||
|
@ -178,7 +177,7 @@ pure nothrow @nogc:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Optimized version of peek() for the case where peek index is 0.
|
/// Optimized version of peek() for the case where peek index is 0.
|
||||||
dchar peek() @safe
|
dchar peek() @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
if(upcomingASCII_ > 0) { return buffer_[bufferOffset_]; }
|
if(upcomingASCII_ > 0) { return buffer_[bufferOffset_]; }
|
||||||
if(characterCount_ <= charIndex_) { return '\0'; }
|
if(characterCount_ <= charIndex_) { return '\0'; }
|
||||||
|
@ -195,13 +194,13 @@ pure nothrow @nogc:
|
||||||
/// case, '\0' will be returned.
|
/// case, '\0' will be returned.
|
||||||
///
|
///
|
||||||
/// Returns: Byte at specified position or '\0' if outside of the buffer.
|
/// Returns: Byte at specified position or '\0' if outside of the buffer.
|
||||||
char peekByte(const size_t index) @safe
|
char peekByte(const size_t index) @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
return characterCount_ > (charIndex_ + index) ? buffer_[bufferOffset_ + index] : '\0';
|
return characterCount_ > (charIndex_ + index) ? buffer_[bufferOffset_ + index] : '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Optimized version of peekByte() for the case where peek byte index is 0.
|
/// Optimized version of peekByte() for the case where peek byte index is 0.
|
||||||
char peekByte() @safe
|
char peekByte() @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
return characterCount_ > charIndex_ ? buffer_[bufferOffset_] : '\0';
|
return characterCount_ > charIndex_ ? buffer_[bufferOffset_] : '\0';
|
||||||
}
|
}
|
||||||
|
@ -218,7 +217,7 @@ pure nothrow @nogc:
|
||||||
/// slice will be shorter.
|
/// slice will be shorter.
|
||||||
///
|
///
|
||||||
/// Returns: Characters starting at current position or an empty slice if out of bounds.
|
/// Returns: Characters starting at current position or an empty slice if out of bounds.
|
||||||
char[] prefix(const size_t length) @safe
|
char[] prefix(const size_t length) @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
return slice(length);
|
return slice(length);
|
||||||
}
|
}
|
||||||
|
@ -234,7 +233,7 @@ pure nothrow @nogc:
|
||||||
/// this.
|
/// this.
|
||||||
///
|
///
|
||||||
/// Returns: Bytes starting at current position.
|
/// Returns: Bytes starting at current position.
|
||||||
char[] prefixBytes(const size_t length) @safe
|
char[] prefixBytes(const size_t length) @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
assert(length == 0 || bufferOffset_ + length < buffer_.length,
|
assert(length == 0 || bufferOffset_ + length < buffer_.length,
|
||||||
"prefixBytes out of bounds");
|
"prefixBytes out of bounds");
|
||||||
|
@ -251,7 +250,7 @@ pure nothrow @nogc:
|
||||||
/// be shorter.
|
/// be shorter.
|
||||||
///
|
///
|
||||||
/// Returns: Slice into the internal buffer or an empty slice if out of bounds.
|
/// Returns: Slice into the internal buffer or an empty slice if out of bounds.
|
||||||
char[] slice(const size_t end) @safe
|
char[] slice(const size_t end) @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
// Fast path in case the caller has already peek()ed all the way to end.
|
// Fast path in case the caller has already peek()ed all the way to end.
|
||||||
if(end == lastDecodedCharOffset_)
|
if(end == lastDecodedCharOffset_)
|
||||||
|
@ -279,7 +278,7 @@ pure nothrow @nogc:
|
||||||
///
|
///
|
||||||
/// Throws: ReaderException if trying to read past the end of the buffer
|
/// Throws: ReaderException if trying to read past the end of the buffer
|
||||||
/// or if invalid data is read.
|
/// or if invalid data is read.
|
||||||
dchar get() @safe
|
dchar get() @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
const result = peek();
|
const result = peek();
|
||||||
forward();
|
forward();
|
||||||
|
@ -291,7 +290,7 @@ pure nothrow @nogc:
|
||||||
/// Params: length = Number or characters (code points, not bytes) to get.
|
/// Params: length = Number or characters (code points, not bytes) to get.
|
||||||
///
|
///
|
||||||
/// Returns: Characters starting at current position.
|
/// Returns: Characters starting at current position.
|
||||||
char[] get(const size_t length) @safe
|
char[] get(const size_t length) @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
auto result = slice(length);
|
auto result = slice(length);
|
||||||
forward(length);
|
forward(length);
|
||||||
|
@ -301,7 +300,7 @@ pure nothrow @nogc:
|
||||||
/// Move current position forward.
|
/// Move current position forward.
|
||||||
///
|
///
|
||||||
/// Params: length = Number of characters to move position forward.
|
/// Params: length = Number of characters to move position forward.
|
||||||
void forward(size_t length) @safe
|
void forward(size_t length) @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
mixin FastCharSearch!"\n\u0085\u2028\u2029"d search;
|
mixin FastCharSearch!"\n\u0085\u2028\u2029"d search;
|
||||||
|
|
||||||
|
@ -356,7 +355,7 @@ pure nothrow @nogc:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move current position forward by one character.
|
/// Move current position forward by one character.
|
||||||
void forward() @trusted
|
void forward() @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
++charIndex_;
|
++charIndex_;
|
||||||
lastDecodedBufferOffset_ = bufferOffset_;
|
lastDecodedBufferOffset_ = bufferOffset_;
|
||||||
|
@ -401,25 +400,24 @@ pure nothrow @nogc:
|
||||||
/// Used to build slices of read data in Reader; to avoid allocations.
|
/// Used to build slices of read data in Reader; to avoid allocations.
|
||||||
SliceBuilder sliceBuilder;
|
SliceBuilder sliceBuilder;
|
||||||
|
|
||||||
@safe pure nothrow @nogc:
|
|
||||||
/// Get a string describing current buffer position, used for error messages.
|
/// Get a string describing current buffer position, used for error messages.
|
||||||
Mark mark() const { return Mark(line_, column_); }
|
Mark mark() const pure nothrow @nogc @safe { return Mark(line_, column_); }
|
||||||
|
|
||||||
/// Get current line number.
|
/// Get current line number.
|
||||||
uint line() const { return line_; }
|
uint line() const @safe pure nothrow @nogc { return line_; }
|
||||||
|
|
||||||
/// Get current column number.
|
/// Get current column number.
|
||||||
uint column() const { return column_; }
|
uint column() const @safe pure nothrow @nogc { return column_; }
|
||||||
|
|
||||||
/// Get index of the current character in the buffer.
|
/// Get index of the current character in the buffer.
|
||||||
size_t charIndex() const { return charIndex_; }
|
size_t charIndex() const @safe pure nothrow @nogc { return charIndex_; }
|
||||||
|
|
||||||
/// Get encoding of the input buffer.
|
/// Get encoding of the input buffer.
|
||||||
Encoding encoding() const { return encoding_; }
|
Encoding encoding() const @safe pure nothrow @nogc { return encoding_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Update upcomingASCII_ (should be called forward()ing over a UTF-8 sequence)
|
// Update upcomingASCII_ (should be called forward()ing over a UTF-8 sequence)
|
||||||
void checkASCII()
|
void checkASCII() @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
upcomingASCII_ = countASCII(buffer_[bufferOffset_ .. $]);
|
upcomingASCII_ = countASCII(buffer_[bufferOffset_ .. $]);
|
||||||
}
|
}
|
||||||
|
@ -428,7 +426,7 @@ private:
|
||||||
// lastDecodedCharOffset_/lastDecodedBufferOffset_ and update them.
|
// lastDecodedCharOffset_/lastDecodedBufferOffset_ and update them.
|
||||||
//
|
//
|
||||||
// Does not advance the buffer position. Used in peek() and slice().
|
// Does not advance the buffer position. Used in peek() and slice().
|
||||||
dchar decodeNext()
|
dchar decodeNext() @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
assert(lastDecodedBufferOffset_ < buffer_.length,
|
assert(lastDecodedBufferOffset_ < buffer_.length,
|
||||||
"Attempted to decode past the end of YAML buffer");
|
"Attempted to decode past the end of YAML buffer");
|
||||||
|
@ -453,7 +451,6 @@ private:
|
||||||
/// See begin() documentation.
|
/// See begin() documentation.
|
||||||
struct SliceBuilder
|
struct SliceBuilder
|
||||||
{
|
{
|
||||||
pure nothrow @nogc:
|
|
||||||
private:
|
private:
|
||||||
// No copying by the user.
|
// No copying by the user.
|
||||||
@disable this(this);
|
@disable this(this);
|
||||||
|
@ -474,7 +471,7 @@ private:
|
||||||
// The number of elements currently in endStack_.
|
// The number of elements currently in endStack_.
|
||||||
size_t endStackUsed_ = 0;
|
size_t endStackUsed_ = 0;
|
||||||
|
|
||||||
@safe const invariant()
|
@safe const pure nothrow @nogc invariant()
|
||||||
{
|
{
|
||||||
if(!inProgress) { return; }
|
if(!inProgress) { return; }
|
||||||
assert(end_ <= reader_.bufferOffset_, "Slice ends after buffer position");
|
assert(end_ <= reader_.bufferOffset_, "Slice ends after buffer position");
|
||||||
|
@ -482,7 +479,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is a slice currently being built?
|
// Is a slice currently being built?
|
||||||
bool inProgress() @safe const
|
bool inProgress() @safe const pure nothrow @nogc
|
||||||
{
|
{
|
||||||
assert(start_ == size_t.max ? end_ == size_t.max : end_ != size_t.max,
|
assert(start_ == size_t.max ? end_ == size_t.max : end_ != size_t.max,
|
||||||
"start_/end_ are not consistent");
|
"start_/end_ are not consistent");
|
||||||
|
@ -500,7 +497,7 @@ public:
|
||||||
/// forward() move the position. E.g. it is valid to extend a slice by write()-ing
|
/// forward() move the position. E.g. it is valid to extend a slice by write()-ing
|
||||||
/// a string just returned by get() - but not one returned by prefix() unless the
|
/// a string just returned by get() - but not one returned by prefix() unless the
|
||||||
/// position has changed since the prefix() call.
|
/// position has changed since the prefix() call.
|
||||||
void begin() @system
|
void begin() @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
assert(!inProgress, "Beginning a slice while another slice is being built");
|
assert(!inProgress, "Beginning a slice while another slice is being built");
|
||||||
assert(endStackUsed_ == 0, "Slice stack not empty at slice begin");
|
assert(endStackUsed_ == 0, "Slice stack not empty at slice begin");
|
||||||
|
@ -516,7 +513,7 @@ public:
|
||||||
///
|
///
|
||||||
/// Returns a string; once a slice is finished it is definitive that its contents
|
/// Returns a string; once a slice is finished it is definitive that its contents
|
||||||
/// will not be changed.
|
/// will not be changed.
|
||||||
char[] finish() @system
|
char[] finish() @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
assert(inProgress, "finish called without begin");
|
assert(inProgress, "finish called without begin");
|
||||||
assert(endStackUsed_ == 0, "Finishing a slice with running transactions.");
|
assert(endStackUsed_ == 0, "Finishing a slice with running transactions.");
|
||||||
|
@ -534,7 +531,7 @@ public:
|
||||||
/// end of the slice being built, the slice is extended (trivial operation).
|
/// end of the slice being built, the slice is extended (trivial operation).
|
||||||
///
|
///
|
||||||
/// See_Also: begin
|
/// See_Also: begin
|
||||||
void write(char[] str) @system
|
void write(char[] str) @trusted pure nothrow @nogc
|
||||||
{
|
{
|
||||||
assert(inProgress, "write called without begin");
|
assert(inProgress, "write called without begin");
|
||||||
assert(end_ <= reader_.bufferOffset_,
|
assert(end_ <= reader_.bufferOffset_,
|
||||||
|
@ -561,7 +558,7 @@ public:
|
||||||
/// Data can only be written up to the current position in the Reader buffer.
|
/// Data can only be written up to the current position in the Reader buffer.
|
||||||
///
|
///
|
||||||
/// See_Also: begin
|
/// See_Also: begin
|
||||||
void write(dchar c) @system
|
void write(dchar c) @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
assert(inProgress, "write called without begin");
|
assert(inProgress, "write called without begin");
|
||||||
if(c < 0x80)
|
if(c < 0x80)
|
||||||
|
@ -588,7 +585,7 @@ public:
|
||||||
/// position = Position to insert the character at in code units, not code points.
|
/// position = Position to insert the character at in code units, not code points.
|
||||||
/// Must be less than slice length(); a previously returned length()
|
/// Must be less than slice length(); a previously returned length()
|
||||||
/// can be used.
|
/// can be used.
|
||||||
void insert(const dchar c, const size_t position) @system
|
void insert(const dchar c, const size_t position) @system pure nothrow @nogc
|
||||||
{
|
{
|
||||||
assert(inProgress, "insert called without begin");
|
assert(inProgress, "insert called without begin");
|
||||||
assert(start_ + position <= end_, "Trying to insert after the end of the slice");
|
assert(start_ + position <= end_, "Trying to insert after the end of the slice");
|
||||||
|
@ -612,7 +609,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current length of the slice.
|
/// Get the current length of the slice.
|
||||||
size_t length() @safe const
|
size_t length() @safe const pure nothrow @nogc
|
||||||
{
|
{
|
||||||
return end_ - start_;
|
return end_ - start_;
|
||||||
}
|
}
|
||||||
|
@ -622,7 +619,6 @@ public:
|
||||||
/// Can be used to save and revert back to slice state.
|
/// Can be used to save and revert back to slice state.
|
||||||
struct Transaction
|
struct Transaction
|
||||||
{
|
{
|
||||||
@system pure nothrow @nogc:
|
|
||||||
private:
|
private:
|
||||||
// The slice builder affected by the transaction.
|
// The slice builder affected by the transaction.
|
||||||
SliceBuilder* builder_ = null;
|
SliceBuilder* builder_ = null;
|
||||||
|
@ -639,7 +635,7 @@ public:
|
||||||
/// ended either by commit()-ing or reverting through the destructor.
|
/// ended either by commit()-ing or reverting through the destructor.
|
||||||
///
|
///
|
||||||
/// Saves the current state of a slice.
|
/// Saves the current state of a slice.
|
||||||
this(ref SliceBuilder builder)
|
this(ref SliceBuilder builder) @system pure nothrow @nogc
|
||||||
{
|
{
|
||||||
builder_ = &builder;
|
builder_ = &builder;
|
||||||
stackLevel_ = builder_.endStackUsed_;
|
stackLevel_ = builder_.endStackUsed_;
|
||||||
|
@ -653,7 +649,7 @@ public:
|
||||||
///
|
///
|
||||||
/// Does nothing for a default-initialized transaction (the transaction has not
|
/// Does nothing for a default-initialized transaction (the transaction has not
|
||||||
/// been started yet).
|
/// been started yet).
|
||||||
void commit()
|
void commit() @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
assert(!committed_, "Can't commit a transaction more than once");
|
assert(!committed_, "Can't commit a transaction more than once");
|
||||||
|
|
||||||
|
@ -667,7 +663,7 @@ public:
|
||||||
/// Destroy the transaction and revert it if it hasn't been committed yet.
|
/// Destroy the transaction and revert it if it hasn't been committed yet.
|
||||||
///
|
///
|
||||||
/// Does nothing for a default-initialized transaction.
|
/// Does nothing for a default-initialized transaction.
|
||||||
~this()
|
~this() @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
if(builder_ is null || committed_) { return; }
|
if(builder_ is null || committed_) { return; }
|
||||||
assert(builder_.endStackUsed_ == stackLevel_ + 1,
|
assert(builder_.endStackUsed_ == stackLevel_ + 1,
|
||||||
|
@ -681,7 +677,7 @@ private:
|
||||||
// Push the current end of the slice so we can revert to it if needed.
|
// Push the current end of the slice so we can revert to it if needed.
|
||||||
//
|
//
|
||||||
// Used by Transaction.
|
// Used by Transaction.
|
||||||
void push() @system
|
void push() @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
assert(inProgress, "push called without begin");
|
assert(inProgress, "push called without begin");
|
||||||
assert(endStackUsed_ < endStack_.length, "Slice stack overflow");
|
assert(endStackUsed_ < endStack_.length, "Slice stack overflow");
|
||||||
|
@ -692,7 +688,7 @@ private:
|
||||||
// value, reverting changes since the old end was pushed.
|
// value, reverting changes since the old end was pushed.
|
||||||
//
|
//
|
||||||
// Used by Transaction.
|
// Used by Transaction.
|
||||||
void pop() @system
|
void pop() @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
assert(inProgress, "pop called without begin");
|
assert(inProgress, "pop called without begin");
|
||||||
assert(endStackUsed_ > 0, "Trying to pop an empty slice stack");
|
assert(endStackUsed_ > 0, "Trying to pop an empty slice stack");
|
||||||
|
@ -703,7 +699,7 @@ private:
|
||||||
// changes made since pushing the old end.
|
// changes made since pushing the old end.
|
||||||
//
|
//
|
||||||
// Used by Transaction.
|
// Used by Transaction.
|
||||||
void apply() @system
|
void apply() @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
assert(inProgress, "apply called without begin");
|
assert(inProgress, "apply called without begin");
|
||||||
assert(endStackUsed_ > 0, "Trying to apply an empty slice stack");
|
assert(endStackUsed_ > 0, "Trying to apply an empty slice stack");
|
||||||
|
@ -823,7 +819,7 @@ auto toUTF8(ubyte[] input, const UTFEncoding encoding) @safe pure nothrow
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine if all characters (code points, not bytes) in a string are printable.
|
/// Determine if all characters (code points, not bytes) in a string are printable.
|
||||||
bool isPrintableValidUTF8(const char[] chars) @trusted pure nothrow @nogc
|
bool isPrintableValidUTF8(const char[] chars) @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
// This is oversized (only 128 entries are necessary) simply because having 256
|
// This is oversized (only 128 entries are necessary) simply because having 256
|
||||||
// entries improves performance... for some reason (alignment?)
|
// entries improves performance... for some reason (alignment?)
|
||||||
|
@ -1041,7 +1037,7 @@ void test1Byte(R)()
|
||||||
// assert(collectException(reader.peek(2)));
|
// assert(collectException(reader.peek(2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@system unittest
|
||||||
{
|
{
|
||||||
testEndian!Reader();
|
testEndian!Reader();
|
||||||
testPeekPrefixForward!Reader();
|
testPeekPrefixForward!Reader();
|
||||||
|
|
|
@ -48,7 +48,7 @@ final class Representer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// Representer functions indexed by types.
|
// Representer functions indexed by types.
|
||||||
Node function(ref Node, Representer)[TypeInfo] representers_;
|
Node function(ref Node, Representer) @safe[TypeInfo] representers_;
|
||||||
// Default style for scalar nodes.
|
// Default style for scalar nodes.
|
||||||
ScalarStyle defaultScalarStyle_ = ScalarStyle.Invalid;
|
ScalarStyle defaultScalarStyle_ = ScalarStyle.Invalid;
|
||||||
// Default style for collection nodes.
|
// Default style for collection nodes.
|
||||||
|
@ -82,7 +82,7 @@ final class Representer
|
||||||
}
|
}
|
||||||
|
|
||||||
///Destroy the Representer.
|
///Destroy the Representer.
|
||||||
pure @safe nothrow ~this()
|
~this() pure @safe nothrow
|
||||||
{
|
{
|
||||||
representers_.destroy();
|
representers_.destroy();
|
||||||
representers_ = null;
|
representers_ = null;
|
||||||
|
@ -222,8 +222,8 @@ final class Representer
|
||||||
* }
|
* }
|
||||||
* --------------------
|
* --------------------
|
||||||
*/
|
*/
|
||||||
void addRepresenter(T)(Node function(ref Node, Representer) representer)
|
void addRepresenter(T)(Node function(ref Node, Representer) @safe representer)
|
||||||
@trusted pure
|
@safe pure
|
||||||
{
|
{
|
||||||
assert((typeid(T) in representers_) is null,
|
assert((typeid(T) in representers_) is null,
|
||||||
"Representer function for data type " ~ T.stringof ~
|
"Representer function for data type " ~ T.stringof ~
|
||||||
|
@ -428,7 +428,7 @@ final class Representer
|
||||||
|
|
||||||
package:
|
package:
|
||||||
//Represent a node based on its type, and return the represented result.
|
//Represent a node based on its type, and return the represented result.
|
||||||
Node representData(ref Node data) @system
|
Node representData(ref Node data) @safe
|
||||||
{
|
{
|
||||||
//User types are wrapped in YAMLObject.
|
//User types are wrapped in YAMLObject.
|
||||||
auto type = data.isUserType ? data.as!YAMLObject.type : data.type;
|
auto type = data.isUserType ? data.as!YAMLObject.type : data.type;
|
||||||
|
@ -454,7 +454,7 @@ final class Representer
|
||||||
}
|
}
|
||||||
|
|
||||||
//Represent a node, serializing with specified Serializer.
|
//Represent a node, serializing with specified Serializer.
|
||||||
void represent(ref Serializer serializer, ref Node node) @trusted
|
void represent(ref Serializer serializer, ref Node node) @safe
|
||||||
{
|
{
|
||||||
auto data = representData(node);
|
auto data = representData(node);
|
||||||
serializer.serialize(data);
|
serializer.serialize(data);
|
||||||
|
@ -478,12 +478,12 @@ Node representString(ref Node node, Representer representer) @safe
|
||||||
}
|
}
|
||||||
|
|
||||||
///Represent a bytes _node as a binary scalar.
|
///Represent a bytes _node as a binary scalar.
|
||||||
Node representBytes(ref Node node, Representer representer) @system
|
Node representBytes(ref Node node, Representer representer) @safe
|
||||||
{
|
{
|
||||||
const ubyte[] value = node.as!(ubyte[]);
|
const ubyte[] value = node.as!(ubyte[]);
|
||||||
if(value is null){return representNull(node, representer);}
|
if(value is null){return representNull(node, representer);}
|
||||||
return representer.representScalar("tag:yaml.org,2002:binary",
|
return representer.representScalar("tag:yaml.org,2002:binary",
|
||||||
cast(string)Base64.encode(value),
|
Base64.encode(value).idup,
|
||||||
ScalarStyle.Literal);
|
ScalarStyle.Literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,14 +495,14 @@ Node representBool(ref Node node, Representer representer) @safe
|
||||||
}
|
}
|
||||||
|
|
||||||
///Represent a long _node as an integer scalar.
|
///Represent a long _node as an integer scalar.
|
||||||
Node representLong(ref Node node, Representer representer) @system
|
Node representLong(ref Node node, Representer representer) @safe
|
||||||
{
|
{
|
||||||
return representer.representScalar("tag:yaml.org,2002:int",
|
return representer.representScalar("tag:yaml.org,2002:int",
|
||||||
to!string(node.as!long));
|
to!string(node.as!long));
|
||||||
}
|
}
|
||||||
|
|
||||||
///Represent a real _node as a floating point scalar.
|
///Represent a real _node as a floating point scalar.
|
||||||
Node representReal(ref Node node, Representer representer) @system
|
Node representReal(ref Node node, Representer representer) @safe
|
||||||
{
|
{
|
||||||
real f = node.as!real;
|
real f = node.as!real;
|
||||||
string value = isNaN(f) ? ".nan":
|
string value = isNaN(f) ? ".nan":
|
||||||
|
@ -516,7 +516,7 @@ Node representReal(ref Node node, Representer representer) @system
|
||||||
}
|
}
|
||||||
|
|
||||||
///Represent a SysTime _node as a timestamp.
|
///Represent a SysTime _node as a timestamp.
|
||||||
Node representSysTime(ref Node node, Representer representer) @system
|
Node representSysTime(ref Node node, Representer representer) @safe
|
||||||
{
|
{
|
||||||
return representer.representScalar("tag:yaml.org,2002:timestamp",
|
return representer.representScalar("tag:yaml.org,2002:timestamp",
|
||||||
node.as!SysTime.toISOExtString());
|
node.as!SysTime.toISOExtString());
|
||||||
|
@ -545,15 +545,14 @@ Node representNodes(ref Node node, Representer representer) @safe
|
||||||
}
|
}
|
||||||
|
|
||||||
///Represent a mapping _node as map/ordered map/pairs.
|
///Represent a mapping _node as map/ordered map/pairs.
|
||||||
Node representPairs(ref Node node, Representer representer) @system
|
Node representPairs(ref Node node, Representer representer) @safe
|
||||||
{
|
{
|
||||||
auto pairs = node.as!(Node.Pair[]);
|
auto pairs = node.as!(Node.Pair[]);
|
||||||
|
|
||||||
bool hasDuplicates(Node.Pair[] pairs)
|
bool hasDuplicates(Node.Pair[] pairs) @safe
|
||||||
{
|
{
|
||||||
//TODO this should be replaced by something with deterministic memory allocation.
|
//TODO this should be replaced by something with deterministic memory allocation.
|
||||||
auto keys = redBlackTree!Node();
|
auto keys = redBlackTree!Node();
|
||||||
scope(exit){keys.destroy();}
|
|
||||||
foreach(ref pair; pairs)
|
foreach(ref pair; pairs)
|
||||||
{
|
{
|
||||||
if(pair.key in keys){return true;}
|
if(pair.key in keys){return true;}
|
||||||
|
@ -562,7 +561,7 @@ Node representPairs(ref Node node, Representer representer) @system
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] mapToSequence(Node.Pair[] pairs)
|
Node[] mapToSequence(Node.Pair[] pairs) @safe
|
||||||
{
|
{
|
||||||
Node[] nodes;
|
Node[] nodes;
|
||||||
nodes.length = pairs.length;
|
nodes.length = pairs.length;
|
||||||
|
@ -610,8 +609,8 @@ struct MyStruct
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Node representMyStruct(ref Node node, Representer representer) @system
|
Node representMyStruct(ref Node node, Representer representer) @safe
|
||||||
{
|
{
|
||||||
//The node is guaranteed to be MyStruct as we add representer for MyStruct.
|
//The node is guaranteed to be MyStruct as we add representer for MyStruct.
|
||||||
auto value = node.as!MyStruct;
|
auto value = node.as!MyStruct;
|
||||||
//Using custom scalar format, x:y:z.
|
//Using custom scalar format, x:y:z.
|
||||||
|
@ -658,15 +657,15 @@ class MyClass
|
||||||
}
|
}
|
||||||
|
|
||||||
///Useful for Node.as!string .
|
///Useful for Node.as!string .
|
||||||
override string toString() @trusted
|
override string toString() @safe
|
||||||
{
|
{
|
||||||
return format("MyClass(%s, %s, %s)", x, y, z);
|
return format("MyClass(%s, %s, %s)", x, y, z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Same as representMyStruct.
|
//Same as representMyStruct.
|
||||||
Node representMyClass(ref Node node, Representer representer) @system
|
Node representMyClass(ref Node node, Representer representer) @safe
|
||||||
{
|
{
|
||||||
//The node is guaranteed to be MyClass as we add representer for MyClass.
|
//The node is guaranteed to be MyClass as we add representer for MyClass.
|
||||||
auto value = node.as!MyClass;
|
auto value = node.as!MyClass;
|
||||||
//Using custom scalar format, x:y:z.
|
//Using custom scalar format, x:y:z.
|
||||||
|
@ -677,7 +676,7 @@ Node representMyClass(ref Node node, Representer representer) @system
|
||||||
|
|
||||||
import dyaml.stream;
|
import dyaml.stream;
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
foreach(r; [&representMyStruct,
|
foreach(r; [&representMyStruct,
|
||||||
&representMyStructSeq,
|
&representMyStructSeq,
|
||||||
|
@ -691,7 +690,7 @@ unittest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
auto dumper = Dumper(new YMemoryStream());
|
auto dumper = Dumper(new YMemoryStream());
|
||||||
auto representer = new Representer;
|
auto representer = new Representer;
|
||||||
|
|
|
@ -70,7 +70,7 @@ final class Resolver
|
||||||
}
|
}
|
||||||
|
|
||||||
///Destroy the Resolver.
|
///Destroy the Resolver.
|
||||||
pure @safe nothrow ~this()
|
~this() pure @safe nothrow
|
||||||
{
|
{
|
||||||
yamlImplicitResolvers_.destroy();
|
yamlImplicitResolvers_.destroy();
|
||||||
yamlImplicitResolvers_ = null;
|
yamlImplicitResolvers_ = null;
|
||||||
|
@ -169,13 +169,13 @@ final class Resolver
|
||||||
else if(kind == NodeID.Mapping) {return defaultMappingTag_;}
|
else if(kind == NodeID.Mapping) {return defaultMappingTag_;}
|
||||||
assert(false, "This line of code should never be reached");
|
assert(false, "This line of code should never be reached");
|
||||||
}
|
}
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Resolver unittest");
|
writeln("D:YAML Resolver unittest");
|
||||||
|
|
||||||
auto resolver = new Resolver();
|
auto resolver = new Resolver();
|
||||||
|
|
||||||
bool tagMatch(string tag, string[] values)
|
bool tagMatch(string tag, string[] values) @safe
|
||||||
{
|
{
|
||||||
string expected = tag;
|
string expected = tag;
|
||||||
foreach(value; values)
|
foreach(value; values)
|
||||||
|
|
|
@ -171,7 +171,7 @@ final class Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destroy the scanner.
|
/// Destroy the scanner.
|
||||||
@trusted ~this()
|
~this() @trusted
|
||||||
{
|
{
|
||||||
tokens_.destroy();
|
tokens_.destroy();
|
||||||
indents_.destroy();
|
indents_.destroy();
|
||||||
|
@ -233,14 +233,14 @@ final class Scanner
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Build an error message in msgBuffer_ and return it as a string.
|
/// Build an error message in msgBuffer_ and return it as a string.
|
||||||
string buildMsg(S ...)(S args) @trusted pure nothrow @nogc
|
string buildMsg(S ...)(S args) @trusted
|
||||||
{
|
{
|
||||||
return cast(string)msgBuffer_.printNoGC(args);
|
return cast(string)msgBuffer_.printNoGC(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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) @safe pure nothrow @nogc
|
string expected(T)(string expected, T found)
|
||||||
{
|
{
|
||||||
return buildMsg("expected ", expected, ", but found ", found);
|
return buildMsg("expected ", expected, ", but found ", found);
|
||||||
}
|
}
|
||||||
|
@ -489,7 +489,7 @@ final class Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add DOCUMENT-START or DOCUMENT-END token.
|
/// Add DOCUMENT-START or DOCUMENT-END token.
|
||||||
void fetchDocumentIndicator(TokenID id)() @safe
|
void fetchDocumentIndicator(TokenID id)()
|
||||||
if(id == TokenID.DocumentStart || id == TokenID.DocumentEnd)
|
if(id == TokenID.DocumentStart || id == TokenID.DocumentEnd)
|
||||||
{
|
{
|
||||||
// Set indentation to -1 .
|
// Set indentation to -1 .
|
||||||
|
@ -508,7 +508,7 @@ final class Scanner
|
||||||
alias fetchDocumentIndicator!(TokenID.DocumentEnd) fetchDocumentEnd;
|
alias fetchDocumentIndicator!(TokenID.DocumentEnd) fetchDocumentEnd;
|
||||||
|
|
||||||
/// Add FLOW-SEQUENCE-START or FLOW-MAPPING-START token.
|
/// Add FLOW-SEQUENCE-START or FLOW-MAPPING-START token.
|
||||||
void fetchFlowCollectionStart(TokenID id)() @trusted
|
void fetchFlowCollectionStart(TokenID id)() @safe
|
||||||
{
|
{
|
||||||
// '[' and '{' may start a simple key.
|
// '[' and '{' may start a simple key.
|
||||||
savePossibleSimpleKey();
|
savePossibleSimpleKey();
|
||||||
|
@ -526,7 +526,7 @@ final class Scanner
|
||||||
alias fetchFlowCollectionStart!(TokenID.FlowMappingStart) fetchFlowMappingStart;
|
alias fetchFlowCollectionStart!(TokenID.FlowMappingStart) fetchFlowMappingStart;
|
||||||
|
|
||||||
/// Add FLOW-SEQUENCE-START or FLOW-MAPPING-START token.
|
/// Add FLOW-SEQUENCE-START or FLOW-MAPPING-START token.
|
||||||
void fetchFlowCollectionEnd(TokenID id)() @safe
|
void fetchFlowCollectionEnd(TokenID id)()
|
||||||
{
|
{
|
||||||
// Reset possible simple key on the current level.
|
// Reset possible simple key on the current level.
|
||||||
removePossibleSimpleKey();
|
removePossibleSimpleKey();
|
||||||
|
@ -560,7 +560,7 @@ final class Scanner
|
||||||
///
|
///
|
||||||
/// Params: type = String representing the token type we might need to add.
|
/// Params: type = String representing the token type we might need to add.
|
||||||
/// id = Token type we might need to add.
|
/// id = Token type we might need to add.
|
||||||
void blockChecks(string type, TokenID id)() @safe
|
void blockChecks(string type, TokenID id)()
|
||||||
{
|
{
|
||||||
enum context = type ~ " keys are not allowed here";
|
enum context = type ~ " keys are not allowed here";
|
||||||
// Are we allowed to start a key (not neccesarily a simple one)?
|
// Are we allowed to start a key (not neccesarily a simple one)?
|
||||||
|
@ -659,7 +659,7 @@ final class Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add ALIAS or ANCHOR token.
|
/// Add ALIAS or ANCHOR token.
|
||||||
void fetchAnchor_(TokenID id)() @trusted
|
void fetchAnchor_(TokenID id)() @safe
|
||||||
if(id == TokenID.Alias || id == TokenID.Anchor)
|
if(id == TokenID.Alias || id == TokenID.Anchor)
|
||||||
{
|
{
|
||||||
// ALIAS/ANCHOR could be a simple key.
|
// ALIAS/ANCHOR could be a simple key.
|
||||||
|
@ -677,7 +677,7 @@ final class Scanner
|
||||||
alias fetchAnchor_!(TokenID.Anchor) fetchAnchor;
|
alias fetchAnchor_!(TokenID.Anchor) fetchAnchor;
|
||||||
|
|
||||||
/// Add TAG token.
|
/// Add TAG token.
|
||||||
void fetchTag() @trusted
|
void fetchTag() @safe
|
||||||
{
|
{
|
||||||
//TAG could start a simple key.
|
//TAG could start a simple key.
|
||||||
savePossibleSimpleKey();
|
savePossibleSimpleKey();
|
||||||
|
@ -689,7 +689,7 @@ final class Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add block SCALAR token.
|
/// Add block SCALAR token.
|
||||||
void fetchBlockScalar(ScalarStyle style)() @trusted
|
void fetchBlockScalar(ScalarStyle style)() @safe
|
||||||
if(style == ScalarStyle.Literal || style == ScalarStyle.Folded)
|
if(style == ScalarStyle.Literal || style == ScalarStyle.Folded)
|
||||||
{
|
{
|
||||||
// Reset possible simple key on the current level.
|
// Reset possible simple key on the current level.
|
||||||
|
@ -707,7 +707,7 @@ final class Scanner
|
||||||
alias fetchBlockScalar!(ScalarStyle.Folded) fetchFolded;
|
alias fetchBlockScalar!(ScalarStyle.Folded) fetchFolded;
|
||||||
|
|
||||||
/// Add quoted flow SCALAR token.
|
/// Add quoted flow SCALAR token.
|
||||||
void fetchFlowScalar(ScalarStyle quotes)() @safe
|
void fetchFlowScalar(ScalarStyle quotes)()
|
||||||
{
|
{
|
||||||
// A flow scalar could be a simple key.
|
// A flow scalar could be a simple key.
|
||||||
savePossibleSimpleKey();
|
savePossibleSimpleKey();
|
||||||
|
@ -828,7 +828,7 @@ final class Scanner
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
///
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
||||||
void scanAlphaNumericToSlice(string name)(const Mark startMark) @system
|
void scanAlphaNumericToSlice(string name)(const Mark startMark)
|
||||||
{
|
{
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
dchar c = reader_.peek();
|
dchar c = reader_.peek();
|
||||||
|
@ -855,7 +855,7 @@ final class 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.
|
||||||
void scanToNextBreakToSlice() @system
|
void scanToNextBreakToSlice() @safe
|
||||||
{
|
{
|
||||||
uint length = 0;
|
uint length = 0;
|
||||||
while(!searchAllBreaks.canFind(reader_.peek(length)))
|
while(!searchAllBreaks.canFind(reader_.peek(length)))
|
||||||
|
@ -905,7 +905,7 @@ final class Scanner
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scan directive token.
|
/// Scan directive token.
|
||||||
Token scanDirective() @trusted
|
Token scanDirective() @safe
|
||||||
{
|
{
|
||||||
Mark startMark = reader_.mark;
|
Mark startMark = reader_.mark;
|
||||||
// Skip the '%'.
|
// Skip the '%'.
|
||||||
|
@ -949,7 +949,7 @@ final class Scanner
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
///
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
||||||
void scanDirectiveNameToSlice(const Mark startMark) @system
|
void scanDirectiveNameToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
// Scan directive name.
|
// Scan directive name.
|
||||||
scanAlphaNumericToSlice!"a directive"(startMark);
|
scanAlphaNumericToSlice!"a directive"(startMark);
|
||||||
|
@ -966,7 +966,7 @@ final class Scanner
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
///
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
||||||
void scanYAMLDirectiveValueToSlice(const Mark startMark) @system
|
void scanYAMLDirectiveValueToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
findNextNonSpace();
|
findNextNonSpace();
|
||||||
|
|
||||||
|
@ -999,7 +999,7 @@ final class Scanner
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
///
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
||||||
void scanYAMLDirectiveNumberToSlice(const Mark startMark) @system
|
void scanYAMLDirectiveNumberToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
if(!isDigit(reader_.peek()))
|
if(!isDigit(reader_.peek()))
|
||||||
{
|
{
|
||||||
|
@ -1023,7 +1023,7 @@ final class Scanner
|
||||||
/// 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.
|
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
||||||
uint scanTagDirectiveValueToSlice(const Mark startMark) @system
|
uint scanTagDirectiveValueToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
findNextNonSpace();
|
findNextNonSpace();
|
||||||
const startLength = reader_.sliceBuilder.length;
|
const startLength = reader_.sliceBuilder.length;
|
||||||
|
@ -1042,7 +1042,7 @@ final class Scanner
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
///
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
||||||
void scanTagDirectiveHandleToSlice(const Mark startMark) @system
|
void scanTagDirectiveHandleToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
scanTagHandleToSlice!"directive"(startMark);
|
scanTagHandleToSlice!"directive"(startMark);
|
||||||
if(error_) { return; }
|
if(error_) { return; }
|
||||||
|
@ -1057,7 +1057,7 @@ final class Scanner
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
///
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
||||||
void scanTagDirectivePrefixToSlice(const Mark startMark) @system
|
void scanTagDirectivePrefixToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
scanTagURIToSlice!"directive"(startMark);
|
scanTagURIToSlice!"directive"(startMark);
|
||||||
if(" \0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek())) { return; }
|
if(" \0\n\r\u0085\u2028\u2029"d.canFind(reader_.peek())) { return; }
|
||||||
|
@ -1094,7 +1094,7 @@ final class Scanner
|
||||||
/// 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.
|
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
||||||
Token scanAnchor(const TokenID id) @trusted
|
Token scanAnchor(const TokenID id) @safe
|
||||||
{
|
{
|
||||||
const startMark = reader_.mark;
|
const startMark = reader_.mark;
|
||||||
const dchar i = reader_.get();
|
const dchar i = reader_.get();
|
||||||
|
@ -1130,7 +1130,7 @@ final class Scanner
|
||||||
/// Scan a tag token.
|
/// Scan a tag token.
|
||||||
///
|
///
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
||||||
Token scanTag() @trusted
|
Token scanTag() @safe
|
||||||
{
|
{
|
||||||
const startMark = reader_.mark;
|
const startMark = reader_.mark;
|
||||||
dchar c = reader_.peek(1);
|
dchar c = reader_.peek(1);
|
||||||
|
@ -1448,7 +1448,7 @@ final class 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.
|
||||||
Tuple!(uint, Mark) scanBlockScalarIndentationToSlice() @system
|
Tuple!(uint, Mark) scanBlockScalarIndentationToSlice() @safe
|
||||||
{
|
{
|
||||||
uint maxIndent;
|
uint maxIndent;
|
||||||
Mark endMark = reader_.mark;
|
Mark endMark = reader_.mark;
|
||||||
|
@ -1472,7 +1472,7 @@ final class 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.
|
||||||
Mark scanBlockScalarBreaksToSlice(const uint indent) @trusted
|
Mark scanBlockScalarBreaksToSlice(const uint indent) @safe
|
||||||
{
|
{
|
||||||
Mark endMark = reader_.mark;
|
Mark endMark = reader_.mark;
|
||||||
|
|
||||||
|
@ -1490,7 +1490,7 @@ final class 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.
|
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
||||||
Token scanFlowScalar(const ScalarStyle quotes) @trusted
|
Token scanFlowScalar(const ScalarStyle quotes) @safe
|
||||||
{
|
{
|
||||||
const startMark = reader_.mark;
|
const startMark = reader_.mark;
|
||||||
const quote = reader_.get();
|
const quote = reader_.get();
|
||||||
|
@ -1521,7 +1521,7 @@ final class Scanner
|
||||||
///
|
///
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
/// 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)
|
||||||
@system
|
@safe
|
||||||
{
|
{
|
||||||
for(;;) with(ScalarStyle)
|
for(;;) with(ScalarStyle)
|
||||||
{
|
{
|
||||||
|
@ -1635,7 +1635,7 @@ final class Scanner
|
||||||
/// spaces into that slice.
|
/// spaces into that slice.
|
||||||
///
|
///
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
||||||
void scanFlowScalarSpacesToSlice(const Mark startMark) @system
|
void scanFlowScalarSpacesToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
// Increase length as long as we see whitespace.
|
// Increase length as long as we see whitespace.
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
|
@ -1680,7 +1680,7 @@ final class Scanner
|
||||||
/// line breaks into that slice.
|
/// line breaks into that slice.
|
||||||
///
|
///
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
||||||
bool scanFlowScalarBreaksToSlice(const Mark startMark) @system
|
bool scanFlowScalarBreaksToSlice(const Mark startMark) @safe
|
||||||
{
|
{
|
||||||
// True if at least one line break was found.
|
// True if at least one line break was found.
|
||||||
bool anyBreaks;
|
bool anyBreaks;
|
||||||
|
@ -1873,7 +1873,7 @@ final class Scanner
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
///
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
||||||
void scanTagHandleToSlice(string name)(const Mark startMark) @system
|
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;
|
||||||
|
@ -1910,7 +1910,7 @@ final class Scanner
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
///
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
||||||
void scanTagURIToSlice(string name)(const Mark startMark) @trusted
|
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.
|
||||||
dchar c = reader_.peek();
|
dchar c = reader_.peek();
|
||||||
|
@ -1952,7 +1952,7 @@ final class Scanner
|
||||||
/// characters into that slice.
|
/// characters into that slice.
|
||||||
///
|
///
|
||||||
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
/// In case of an error, error_ is set. Use throwIfError() to handle this.
|
||||||
void scanURIEscapesToSlice(string name)(const Mark startMark) @system
|
void scanURIEscapesToSlice(string name)(const Mark startMark)
|
||||||
{
|
{
|
||||||
// URI escapes encode a UTF-8 string. We store UTF-8 code units here for
|
// URI escapes encode a UTF-8 string. We store UTF-8 code units here for
|
||||||
// decoding into UTF-32.
|
// decoding into UTF-32.
|
||||||
|
@ -1967,7 +1967,7 @@ final class Scanner
|
||||||
//
|
//
|
||||||
// Returns the number of bytes used by the dchar in bytes on success,
|
// Returns the number of bytes used by the dchar in bytes on success,
|
||||||
// size_t.max on failure.
|
// size_t.max on failure.
|
||||||
static size_t getDchar(char[] bytes, Reader reader_)
|
static size_t getDchar(char[] bytes, Reader reader_) @trusted
|
||||||
{
|
{
|
||||||
size_t nextChar;
|
size_t nextChar;
|
||||||
dchar c;
|
dchar c;
|
||||||
|
@ -1985,7 +1985,7 @@ final class Scanner
|
||||||
reader_.sliceBuilder.write(c);
|
reader_.sliceBuilder.write(c);
|
||||||
if(bytes.length - nextChar > 0)
|
if(bytes.length - nextChar > 0)
|
||||||
{
|
{
|
||||||
core.stdc.string.memmove(bytes.ptr, bytes.ptr + nextChar,
|
core.stdc.string.memmove(&bytes[0], &bytes[nextChar],
|
||||||
bytes.length - nextChar);
|
bytes.length - nextChar);
|
||||||
}
|
}
|
||||||
return bytes.length - nextChar;
|
return bytes.length - nextChar;
|
||||||
|
@ -2081,7 +2081,7 @@ final class Scanner
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// A nothrow function that converts a dchar[] to a string.
|
/// A nothrow function that converts a dchar[] to a string.
|
||||||
string utf32To8(C)(C[] str) @safe pure nothrow
|
string utf32To8(C)(C[] str)
|
||||||
if(is(Unqual!C == dchar))
|
if(is(Unqual!C == dchar))
|
||||||
{
|
{
|
||||||
try { return str.to!string; }
|
try { return str.to!string; }
|
||||||
|
|
|
@ -82,7 +82,7 @@ struct Serializer
|
||||||
}
|
}
|
||||||
|
|
||||||
///Destroy the Serializer.
|
///Destroy the Serializer.
|
||||||
@safe ~this()
|
~this() @safe
|
||||||
{
|
{
|
||||||
emitter_.emit(streamEndEvent(Mark(), Mark()));
|
emitter_.emit(streamEndEvent(Mark(), Mark()));
|
||||||
YAMLVersion_.destroy();
|
YAMLVersion_.destroy();
|
||||||
|
@ -119,7 +119,7 @@ struct Serializer
|
||||||
*
|
*
|
||||||
* Returns: True if the node is anchorable, false otherwise.
|
* Returns: True if the node is anchorable, false otherwise.
|
||||||
*/
|
*/
|
||||||
static bool anchorable(ref Node node) @safe
|
static bool anchorable(ref Node node) @safe
|
||||||
{
|
{
|
||||||
if(node.isScalar)
|
if(node.isScalar)
|
||||||
{
|
{
|
||||||
|
@ -157,7 +157,7 @@ struct Serializer
|
||||||
}
|
}
|
||||||
|
|
||||||
///Generate and return a new anchor.
|
///Generate and return a new anchor.
|
||||||
string generateAnchor() @trusted
|
string generateAnchor() @safe
|
||||||
{
|
{
|
||||||
++lastAnchorID_;
|
++lastAnchorID_;
|
||||||
auto appender = appender!string();
|
auto appender = appender!string();
|
||||||
|
@ -166,7 +166,7 @@ struct Serializer
|
||||||
}
|
}
|
||||||
|
|
||||||
///Serialize a node and all its subnodes.
|
///Serialize a node and all its subnodes.
|
||||||
void serializeNode(ref Node node) @trusted
|
void serializeNode(ref Node node) @safe
|
||||||
{
|
{
|
||||||
//If the node has an anchor, emit an anchor (as aliasEvent) on the
|
//If the node has an anchor, emit an anchor (as aliasEvent) on the
|
||||||
//first occurrence, save it in serializedNodes_, and emit an alias
|
//first occurrence, save it in serializedNodes_, and emit an alias
|
||||||
|
|
|
@ -31,10 +31,11 @@ immutable ubyte[][NBOMS] ByteOrderMarks =
|
||||||
interface YStream
|
interface YStream
|
||||||
{
|
{
|
||||||
void writeExact(const void* buffer, size_t size);
|
void writeExact(const void* buffer, size_t size);
|
||||||
size_t write(const(ubyte)[] buffer);
|
void writeExact(const void[] buffer) @safe;
|
||||||
size_t write(const(char)[] str);
|
size_t write(const(ubyte)[] buffer) @safe;
|
||||||
void flush();
|
size_t write(const(char)[] str) @safe;
|
||||||
@property bool writeable();
|
void flush() @safe;
|
||||||
|
@property bool writeable() @safe;
|
||||||
}
|
}
|
||||||
|
|
||||||
class YMemoryStream : YStream
|
class YMemoryStream : YStream
|
||||||
|
@ -46,20 +47,25 @@ class YMemoryStream : YStream
|
||||||
data ~= cast(ubyte[])buffer[0 .. size];
|
data ~= cast(ubyte[])buffer[0 .. size];
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t write(const(ubyte)[] buffer)
|
void writeExact(const void[] buffer) @trusted
|
||||||
|
{
|
||||||
|
data ~= cast(ubyte[])buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write(const(ubyte)[] buffer) @safe
|
||||||
{
|
{
|
||||||
data ~= buffer;
|
data ~= buffer;
|
||||||
return buffer.length;
|
return buffer.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t write(const(char)[] str)
|
size_t write(const(char)[] str) @safe
|
||||||
{
|
{
|
||||||
return write(cast(const(ubyte)[])str);
|
return write(cast(const(ubyte)[])str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush() {}
|
void flush() @safe {}
|
||||||
|
|
||||||
@property bool writeable() { return true; }
|
@property bool writeable() @safe { return true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
class YFile : YStream
|
class YFile : YStream
|
||||||
|
@ -67,17 +73,17 @@ class YFile : YStream
|
||||||
static import std.stdio;
|
static import std.stdio;
|
||||||
std.stdio.File file;
|
std.stdio.File file;
|
||||||
|
|
||||||
this(string fn)
|
this(string fn) @safe
|
||||||
{
|
{
|
||||||
this.file = std.stdio.File(fn, "w");
|
this.file = std.stdio.File(fn, "w");
|
||||||
}
|
}
|
||||||
|
|
||||||
this(std.stdio.File file)
|
this(std.stdio.File file) @safe
|
||||||
{
|
{
|
||||||
this.file = file;
|
this.file = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@system unittest
|
||||||
{
|
{
|
||||||
import std.stdio : stdout;
|
import std.stdio : stdout;
|
||||||
auto stream = new YFile(stdout);
|
auto stream = new YFile(stdout);
|
||||||
|
@ -89,26 +95,31 @@ class YFile : YStream
|
||||||
this.file.rawWrite(cast(const) buffer[0 .. size]);
|
this.file.rawWrite(cast(const) buffer[0 .. size]);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t write(const(ubyte)[] buffer)
|
void writeExact(const void[] buffer) @trusted
|
||||||
|
{
|
||||||
|
this.file.rawWrite(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write(const(ubyte)[] buffer) @trusted
|
||||||
{
|
{
|
||||||
this.file.rawWrite(buffer);
|
this.file.rawWrite(buffer);
|
||||||
return buffer.length;
|
return buffer.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t write(const(char)[] str)
|
size_t write(const(char)[] str) @trusted
|
||||||
{
|
{
|
||||||
return write(cast(const(ubyte)[])str);
|
return write(cast(ubyte[])str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush()
|
void flush() @safe
|
||||||
{
|
{
|
||||||
this.file.flush();
|
this.file.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
@property bool writeable() { return true; }
|
@property bool writeable() @safe { return true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
import dyaml.dumper, dyaml.loader, dyaml.node;
|
import dyaml.dumper, dyaml.loader, dyaml.node;
|
||||||
import std.file : readText, remove;
|
import std.file : readText, remove;
|
||||||
|
@ -135,7 +146,7 @@ unittest
|
||||||
remove("output.yaml");
|
remove("output.yaml");
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest // #88, #89
|
@safe unittest // #88, #89
|
||||||
{
|
{
|
||||||
import dyaml.dumper, dyaml.loader;
|
import dyaml.dumper, dyaml.loader;
|
||||||
import std.file : remove, read;
|
import std.file : remove, read;
|
||||||
|
@ -147,5 +158,5 @@ unittest // #88, #89
|
||||||
dumper.YAMLVersion = null; // supress directive
|
dumper.YAMLVersion = null; // supress directive
|
||||||
dumper.dump(Loader.fromString("Hello world".dup).load);
|
dumper.dump(Loader.fromString("Hello world".dup).load);
|
||||||
|
|
||||||
assert (cast (char[]) fn.read()[0..3] == "Hel");
|
assert (fn.read()[0..3] == "Hel");
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import std.array;
|
||||||
import std.conv;
|
import std.conv;
|
||||||
import std.file;
|
import std.file;
|
||||||
import std.path;
|
import std.path;
|
||||||
|
import std.traits;
|
||||||
import std.typecons;
|
import std.typecons;
|
||||||
|
|
||||||
package:
|
package:
|
||||||
|
@ -31,7 +32,7 @@ package:
|
||||||
* unittestExt = Extensions of data files needed for the unittest.
|
* unittestExt = Extensions of data files needed for the unittest.
|
||||||
* skipExt = Extensions that must not be used for the unittest.
|
* skipExt = Extensions that must not be used for the unittest.
|
||||||
*/
|
*/
|
||||||
void run(F ...)(string testName, void function(bool, F) testFunction,
|
void run(D)(string testName, D testFunction,
|
||||||
string[] unittestExt, string[] skipExt = [])
|
string[] unittestExt, string[] skipExt = [])
|
||||||
{
|
{
|
||||||
immutable string dataDir = __FILE_FULL_PATH__.dirName ~ "/../../../test/data";
|
immutable string dataDir = __FILE_FULL_PATH__.dirName ~ "/../../../test/data";
|
||||||
|
@ -54,16 +55,25 @@ void run(F ...)(string testName, void function(bool, F) testFunction,
|
||||||
if(extensions.canFind(ext)){continue outer;}
|
if(extensions.canFind(ext)){continue outer;}
|
||||||
}
|
}
|
||||||
|
|
||||||
results ~= execute!F(testName, testFunction, filenames, verbose);
|
results ~= execute(testName, testFunction, filenames, verbose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
results ~= execute!F(testName, testFunction, cast(string[])[], verbose);
|
results ~= execute(testName, testFunction, cast(string[])[], verbose);
|
||||||
}
|
}
|
||||||
display(results, verbose);
|
display(results, verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints an exception if verbosity is turned on.
|
||||||
|
* Params: e = Exception to print.
|
||||||
|
* verbose = Whether verbose mode is enabled.
|
||||||
|
*/
|
||||||
|
void printException(YAMLException e, bool verbose) @trusted
|
||||||
|
{
|
||||||
|
if(verbose) { writeln(typeid(e).toString(), "\n", e); }
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -85,7 +95,7 @@ alias Tuple!(string, "name", string[], "filenames", TestStatus, "kind", string,
|
||||||
*
|
*
|
||||||
* Returns: Test input base filenames and their extensions.
|
* Returns: Test input base filenames and their extensions.
|
||||||
*/
|
*/
|
||||||
string[][string] findTestFilenames(const string dir)
|
string[][string] findTestFilenames(const string dir) @trusted
|
||||||
{
|
{
|
||||||
//Groups of extensions indexed by base names.
|
//Groups of extensions indexed by base names.
|
||||||
string[][string] names;
|
string[][string] names;
|
||||||
|
@ -130,8 +140,8 @@ body
|
||||||
*
|
*
|
||||||
* Returns: Information about the results of the unittest.
|
* Returns: Information about the results of the unittest.
|
||||||
*/
|
*/
|
||||||
Result execute(F ...)(const string testName, void function(bool, F) testFunction,
|
Result execute(D)(const string testName, D testFunction,
|
||||||
string[] filenames, const bool verbose)
|
string[] filenames, const bool verbose) @trusted
|
||||||
{
|
{
|
||||||
if(verbose)
|
if(verbose)
|
||||||
{
|
{
|
||||||
|
@ -144,6 +154,7 @@ Result execute(F ...)(const string testName, void function(bool, F) testFunction
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//Convert filenames to parameters tuple and call the test function.
|
//Convert filenames to parameters tuple and call the test function.
|
||||||
|
alias F = Parameters!D[1..$];
|
||||||
F parameters;
|
F parameters;
|
||||||
stringsToTuple!(F.length - 1, F)(parameters, filenames);
|
stringsToTuple!(F.length - 1, F)(parameters, filenames);
|
||||||
testFunction(verbose, parameters);
|
testFunction(verbose, parameters);
|
||||||
|
@ -167,7 +178,7 @@ Result execute(F ...)(const string testName, void function(bool, F) testFunction
|
||||||
* Params: results = Unittest results.
|
* Params: results = Unittest results.
|
||||||
* verbose = Print verbose output?
|
* verbose = Print verbose output?
|
||||||
*/
|
*/
|
||||||
void display(Result[] results, const bool verbose)
|
void display(Result[] results, const bool verbose) @safe
|
||||||
{
|
{
|
||||||
if(results.length > 0 && !verbose){write("\n");}
|
if(results.length > 0 && !verbose){write("\n");}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import dyaml.token;
|
||||||
/// Params: verbose = Print verbose output?
|
/// Params: verbose = Print verbose output?
|
||||||
/// dataFilename = YAML file to parse.
|
/// dataFilename = YAML file to parse.
|
||||||
/// canonicalFilename = Another file to parse, in canonical YAML format.
|
/// canonicalFilename = Another file to parse, in canonical YAML format.
|
||||||
void testParser(bool verbose, string dataFilename, string canonicalFilename)
|
void testParser(bool verbose, string dataFilename, string canonicalFilename) @safe
|
||||||
{
|
{
|
||||||
auto dataEvents = Loader(dataFilename).parse();
|
auto dataEvents = Loader(dataFilename).parse();
|
||||||
auto canonicalEvents = Loader(canonicalFilename).parse();
|
auto canonicalEvents = Loader(canonicalFilename).parse();
|
||||||
|
@ -38,7 +38,7 @@ void testParser(bool verbose, string dataFilename, string canonicalFilename)
|
||||||
/// Params: verbose = Print verbose output?
|
/// Params: verbose = Print verbose output?
|
||||||
/// dataFilename = YAML file to load.
|
/// dataFilename = YAML file to load.
|
||||||
/// canonicalFilename = Another file to load, in canonical YAML format.
|
/// canonicalFilename = Another file to load, in canonical YAML format.
|
||||||
void testLoader(bool verbose, string dataFilename, string canonicalFilename)
|
void testLoader(bool verbose, string dataFilename, string canonicalFilename) @safe
|
||||||
{
|
{
|
||||||
auto data = Loader(dataFilename).loadAll();
|
auto data = Loader(dataFilename).loadAll();
|
||||||
auto canonical = Loader(canonicalFilename).loadAll();
|
auto canonical = Loader(canonicalFilename).loadAll();
|
||||||
|
@ -62,7 +62,7 @@ void testLoader(bool verbose, string dataFilename, string canonicalFilename)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML comparison unittest");
|
writeln("D:YAML comparison unittest");
|
||||||
run("testParser", &testParser, ["data", "canonical"]);
|
run("testParser", &testParser, ["data", "canonical"]);
|
||||||
|
|
|
@ -23,7 +23,7 @@ import dyaml.test.common;
|
||||||
Node[][string] expected;
|
Node[][string] expected;
|
||||||
|
|
||||||
///Initialize expected.
|
///Initialize expected.
|
||||||
static this()
|
static this() @safe
|
||||||
{
|
{
|
||||||
expected["aliases-cdumper-bug"] = constructAliasesCDumperBug();
|
expected["aliases-cdumper-bug"] = constructAliasesCDumperBug();
|
||||||
expected["construct-binary"] = constructBinary();
|
expected["construct-binary"] = constructBinary();
|
||||||
|
@ -64,15 +64,15 @@ Node.Pair pair(A, B)(A a, B b)
|
||||||
|
|
||||||
///Test cases:
|
///Test cases:
|
||||||
|
|
||||||
Node[] constructAliasesCDumperBug()
|
Node[] constructAliasesCDumperBug() @safe
|
||||||
{
|
{
|
||||||
return [Node(["today", "today"])];
|
return [Node(["today", "today"])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructBinary()
|
Node[] constructBinary() @safe
|
||||||
{
|
{
|
||||||
auto canonical = cast(ubyte[])"GIF89a\x0c\x00\x0c\x00\x84\x00\x00\xff\xff\xf7\xf5\xf5\xee\xe9\xe9\xe5fff\x00\x00\x00\xe7\xe7\xe7^^^\xf3\xf3\xed\x8e\x8e\x8e\xe0\xe0\xe0\x9f\x9f\x9f\x93\x93\x93\xa7\xa7\xa7\x9e\x9e\x9eiiiccc\xa3\xa3\xa3\x84\x84\x84\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9!\xfe\x0eMade with GIMP\x00,\x00\x00\x00\x00\x0c\x00\x0c\x00\x00\x05, \x8e\x810\x9e\xe3@\x14\xe8i\x10\xc4\xd1\x8a\x08\x1c\xcf\x80M$z\xef\xff0\x85p\xb8\xb01f\r\x1b\xce\x01\xc3\x01\x1e\x10' \x82\n\x01\x00;";
|
auto canonical = "GIF89a\x0c\x00\x0c\x00\x84\x00\x00\xff\xff\xf7\xf5\xf5\xee\xe9\xe9\xe5fff\x00\x00\x00\xe7\xe7\xe7^^^\xf3\xf3\xed\x8e\x8e\x8e\xe0\xe0\xe0\x9f\x9f\x9f\x93\x93\x93\xa7\xa7\xa7\x9e\x9e\x9eiiiccc\xa3\xa3\xa3\x84\x84\x84\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9!\xfe\x0eMade with GIMP\x00,\x00\x00\x00\x00\x0c\x00\x0c\x00\x00\x05, \x8e\x810\x9e\xe3@\x14\xe8i\x10\xc4\xd1\x8a\x08\x1c\xcf\x80M$z\xef\xff0\x85p\xb8\xb01f\r\x1b\xce\x01\xc3\x01\x1e\x10' \x82\n\x01\x00;".representation;
|
||||||
auto generic = cast(ubyte[])"GIF89a\x0c\x00\x0c\x00\x84\x00\x00\xff\xff\xf7\xf5\xf5\xee\xe9\xe9\xe5fff\x00\x00\x00\xe7\xe7\xe7^^^\xf3\xf3\xed\x8e\x8e\x8e\xe0\xe0\xe0\x9f\x9f\x9f\x93\x93\x93\xa7\xa7\xa7\x9e\x9e\x9eiiiccc\xa3\xa3\xa3\x84\x84\x84\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9!\xfe\x0eMade with GIMP\x00,\x00\x00\x00\x00\x0c\x00\x0c\x00\x00\x05, \x8e\x810\x9e\xe3@\x14\xe8i\x10\xc4\xd1\x8a\x08\x1c\xcf\x80M$z\xef\xff0\x85p\xb8\xb01f\r\x1b\xce\x01\xc3\x01\x1e\x10' \x82\n\x01\x00;";
|
auto generic = "GIF89a\x0c\x00\x0c\x00\x84\x00\x00\xff\xff\xf7\xf5\xf5\xee\xe9\xe9\xe5fff\x00\x00\x00\xe7\xe7\xe7^^^\xf3\xf3\xed\x8e\x8e\x8e\xe0\xe0\xe0\x9f\x9f\x9f\x93\x93\x93\xa7\xa7\xa7\x9e\x9e\x9eiiiccc\xa3\xa3\xa3\x84\x84\x84\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9!\xfe\x0eMade with GIMP\x00,\x00\x00\x00\x00\x0c\x00\x0c\x00\x00\x05, \x8e\x810\x9e\xe3@\x14\xe8i\x10\xc4\xd1\x8a\x08\x1c\xcf\x80M$z\xef\xff0\x85p\xb8\xb01f\r\x1b\xce\x01\xc3\x01\x1e\x10' \x82\n\x01\x00;".representation;
|
||||||
auto description = "The binary value above is a tiny arrow encoded as a gif image.";
|
auto description = "The binary value above is a tiny arrow encoded as a gif image.";
|
||||||
|
|
||||||
return [Node([pair("canonical", canonical),
|
return [Node([pair("canonical", canonical),
|
||||||
|
@ -80,7 +80,7 @@ Node[] constructBinary()
|
||||||
pair("description", description)])];
|
pair("description", description)])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructBool()
|
Node[] constructBool() @safe
|
||||||
{
|
{
|
||||||
const(bool) a = true;
|
const(bool) a = true;
|
||||||
immutable(bool) b = true;
|
immutable(bool) b = true;
|
||||||
|
@ -97,13 +97,13 @@ Node[] constructBool()
|
||||||
pair("but", [pair("y", "is a string"), pair("n", "is a string")])])];
|
pair("but", [pair("y", "is a string"), pair("n", "is a string")])])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructCustom()
|
Node[] constructCustom() @safe
|
||||||
{
|
{
|
||||||
return [Node([Node(new TestClass(1, 2, 3)),
|
return [Node([Node(new TestClass(1, 2, 3)),
|
||||||
Node(TestStruct(10))])];
|
Node(TestStruct(10))])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructFloat()
|
Node[] constructFloat() @safe
|
||||||
{
|
{
|
||||||
return [Node([pair("canonical", cast(real)685230.15),
|
return [Node([pair("canonical", cast(real)685230.15),
|
||||||
pair("exponential", cast(real)685230.15),
|
pair("exponential", cast(real)685230.15),
|
||||||
|
@ -113,7 +113,7 @@ Node[] constructFloat()
|
||||||
pair("not a number", real.nan)])];
|
pair("not a number", real.nan)])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructInt()
|
Node[] constructInt() @safe
|
||||||
{
|
{
|
||||||
return [Node([pair("canonical", 685230L),
|
return [Node([pair("canonical", 685230L),
|
||||||
pair("decimal", 685230L),
|
pair("decimal", 685230L),
|
||||||
|
@ -123,7 +123,7 @@ Node[] constructInt()
|
||||||
pair("sexagesimal", 685230L)])];
|
pair("sexagesimal", 685230L)])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructMap()
|
Node[] constructMap() @safe
|
||||||
{
|
{
|
||||||
return [Node([pair("Block style",
|
return [Node([pair("Block style",
|
||||||
[pair("Clark", "Evans"),
|
[pair("Clark", "Evans"),
|
||||||
|
@ -135,7 +135,7 @@ Node[] constructMap()
|
||||||
pair("Oren", "Ben-Kiki")])])];
|
pair("Oren", "Ben-Kiki")])])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructMerge()
|
Node[] constructMerge() @safe
|
||||||
{
|
{
|
||||||
return [Node([Node([pair("x", 1L), pair("y", 2L)]),
|
return [Node([Node([pair("x", 1L), pair("y", 2L)]),
|
||||||
Node([pair("x", 0L), pair("y", 2L)]),
|
Node([pair("x", 0L), pair("y", 2L)]),
|
||||||
|
@ -147,7 +147,7 @@ Node[] constructMerge()
|
||||||
Node([pair("x", 1L), pair("label", "center/big"), pair("r", 10L), pair("y", 2L)])])];
|
Node([pair("x", 1L), pair("label", "center/big"), pair("r", 10L), pair("y", 2L)])])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructNull()
|
Node[] constructNull() @safe
|
||||||
{
|
{
|
||||||
return [Node(YAMLNull()),
|
return [Node(YAMLNull()),
|
||||||
Node([pair("empty", YAMLNull()),
|
Node([pair("empty", YAMLNull()),
|
||||||
|
@ -162,7 +162,7 @@ Node[] constructNull()
|
||||||
Node(YAMLNull())])])];
|
Node(YAMLNull())])])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructOMap()
|
Node[] constructOMap() @safe
|
||||||
{
|
{
|
||||||
return [Node([pair("Bestiary",
|
return [Node([pair("Bestiary",
|
||||||
[pair("aardvark", "African pig-like ant eater. Ugly."),
|
[pair("aardvark", "African pig-like ant eater. Ugly."),
|
||||||
|
@ -173,7 +173,7 @@ Node[] constructOMap()
|
||||||
pair("three", 3L)])])];
|
pair("three", 3L)])])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructPairs()
|
Node[] constructPairs() @safe
|
||||||
{
|
{
|
||||||
return [Node([pair("Block tasks",
|
return [Node([pair("Block tasks",
|
||||||
Node([pair("meeting", "with team."),
|
Node([pair("meeting", "with team."),
|
||||||
|
@ -185,7 +185,7 @@ Node[] constructPairs()
|
||||||
pair("meeting", "with boss")], "tag:yaml.org,2002:pairs"))])];
|
pair("meeting", "with boss")], "tag:yaml.org,2002:pairs"))])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructSeq()
|
Node[] constructSeq() @safe
|
||||||
{
|
{
|
||||||
return [Node([pair("Block style",
|
return [Node([pair("Block style",
|
||||||
[Node("Mercury"), Node("Venus"), Node("Earth"), Node("Mars"),
|
[Node("Mercury"), Node("Venus"), Node("Earth"), Node("Mars"),
|
||||||
|
@ -197,7 +197,7 @@ Node[] constructSeq()
|
||||||
Node("Pluto")])])];
|
Node("Pluto")])])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructSet()
|
Node[] constructSet() @safe
|
||||||
{
|
{
|
||||||
return [Node([pair("baseball players",
|
return [Node([pair("baseball players",
|
||||||
[Node("Mark McGwire"), Node("Sammy Sosa"), Node("Ken Griffey")]),
|
[Node("Mark McGwire"), Node("Sammy Sosa"), Node("Ken Griffey")]),
|
||||||
|
@ -205,22 +205,22 @@ Node[] constructSet()
|
||||||
[Node("Boston Red Sox"), Node("Detroit Tigers"), Node("New York Yankees")])])];
|
[Node("Boston Red Sox"), Node("Detroit Tigers"), Node("New York Yankees")])])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructStrASCII()
|
Node[] constructStrASCII() @safe
|
||||||
{
|
{
|
||||||
return [Node("ascii string")];
|
return [Node("ascii string")];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructStr()
|
Node[] constructStr() @safe
|
||||||
{
|
{
|
||||||
return [Node([pair("string", "abcd")])];
|
return [Node([pair("string", "abcd")])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructStrUTF8()
|
Node[] constructStrUTF8() @safe
|
||||||
{
|
{
|
||||||
return [Node("\u042d\u0442\u043e \u0443\u043d\u0438\u043a\u043e\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430")];
|
return [Node("\u042d\u0442\u043e \u0443\u043d\u0438\u043a\u043e\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430")];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructTimestamp()
|
Node[] constructTimestamp() @safe
|
||||||
{
|
{
|
||||||
alias DT = DateTime;
|
alias DT = DateTime;
|
||||||
alias ST = SysTime;
|
alias ST = SysTime;
|
||||||
|
@ -231,7 +231,7 @@ Node[] constructTimestamp()
|
||||||
pair("date (00:00:00Z)", ST(DT(2002, 12, 14), UTC()))])];
|
pair("date (00:00:00Z)", ST(DT(2002, 12, 14), UTC()))])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] constructValue()
|
Node[] constructValue() @safe
|
||||||
{
|
{
|
||||||
return[Node([pair("link with",
|
return[Node([pair("link with",
|
||||||
[Node("library1.dll"), Node("library2.dll")])]),
|
[Node("library1.dll"), Node("library2.dll")])]),
|
||||||
|
@ -240,7 +240,7 @@ Node[] constructValue()
|
||||||
Node([pair("=", "library2.dll"), pair("version", cast(real)2.3)])])])];
|
Node([pair("=", "library2.dll"), pair("version", cast(real)2.3)])])])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] duplicateMergeKey()
|
Node[] duplicateMergeKey() @safe
|
||||||
{
|
{
|
||||||
return [Node([pair("foo", "bar"),
|
return [Node([pair("foo", "bar"),
|
||||||
pair("x", 1L),
|
pair("x", 1L),
|
||||||
|
@ -249,7 +249,7 @@ Node[] duplicateMergeKey()
|
||||||
pair("t", 4L)])];
|
pair("t", 4L)])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] floatRepresenterBug()
|
Node[] floatRepresenterBug() @safe
|
||||||
{
|
{
|
||||||
return [Node([pair(cast(real)1.0, 1L),
|
return [Node([pair(cast(real)1.0, 1L),
|
||||||
pair(real.infinity, 10L),
|
pair(real.infinity, 10L),
|
||||||
|
@ -257,12 +257,12 @@ Node[] floatRepresenterBug()
|
||||||
pair(real.nan, 100L)])];
|
pair(real.nan, 100L)])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] invalidSingleQuoteBug()
|
Node[] invalidSingleQuoteBug() @safe
|
||||||
{
|
{
|
||||||
return [Node([Node("foo \'bar\'"), Node("foo\n\'bar\'")])];
|
return [Node([Node("foo \'bar\'"), Node("foo\n\'bar\'")])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] moreFloats()
|
Node[] moreFloats() @safe
|
||||||
{
|
{
|
||||||
return [Node([Node(cast(real)0.0),
|
return [Node([Node(cast(real)0.0),
|
||||||
Node(cast(real)1.0),
|
Node(cast(real)1.0),
|
||||||
|
@ -273,17 +273,17 @@ Node[] moreFloats()
|
||||||
Node(real.nan)])];
|
Node(real.nan)])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] negativeFloatBug()
|
Node[] negativeFloatBug() @safe
|
||||||
{
|
{
|
||||||
return [Node(cast(real)-1.0)];
|
return [Node(cast(real)-1.0)];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] singleDotFloatBug()
|
Node[] singleDotFloatBug() @safe
|
||||||
{
|
{
|
||||||
return [Node(".")];
|
return [Node(".")];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] timestampBugs()
|
Node[] timestampBugs() @safe
|
||||||
{
|
{
|
||||||
alias DT = DateTime;
|
alias DT = DateTime;
|
||||||
alias ST = SysTime;
|
alias ST = SysTime;
|
||||||
|
@ -296,22 +296,22 @@ Node[] timestampBugs()
|
||||||
Node(ST(DT(2005, 7, 8, 17, 35, 4), 5176000.dur!"hnsecs", UTC()))])];
|
Node(ST(DT(2005, 7, 8, 17, 35, 4), 5176000.dur!"hnsecs", UTC()))])];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] utf16be()
|
Node[] utf16be() @safe
|
||||||
{
|
{
|
||||||
return [Node("UTF-16-BE")];
|
return [Node("UTF-16-BE")];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] utf16le()
|
Node[] utf16le() @safe
|
||||||
{
|
{
|
||||||
return [Node("UTF-16-LE")];
|
return [Node("UTF-16-LE")];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] utf8()
|
Node[] utf8() @safe
|
||||||
{
|
{
|
||||||
return [Node("UTF-8")];
|
return [Node("UTF-8")];
|
||||||
}
|
}
|
||||||
|
|
||||||
Node[] utf8implicit()
|
Node[] utf8implicit() @safe
|
||||||
{
|
{
|
||||||
return [Node("implicit UTF-8")];
|
return [Node("implicit UTF-8")];
|
||||||
}
|
}
|
||||||
|
@ -321,7 +321,7 @@ class TestClass
|
||||||
{
|
{
|
||||||
int x, y, z;
|
int x, y, z;
|
||||||
|
|
||||||
this(int x, int y, int z)
|
this(int x, int y, int z) @safe
|
||||||
{
|
{
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
|
@ -330,7 +330,7 @@ class TestClass
|
||||||
|
|
||||||
//Any D:YAML type must have a custom opCmp operator.
|
//Any D:YAML type must have a custom opCmp operator.
|
||||||
//This is used for ordering in mappings.
|
//This is used for ordering in mappings.
|
||||||
override int opCmp(Object o)
|
override int opCmp(Object o) @safe
|
||||||
{
|
{
|
||||||
TestClass s = cast(TestClass)o;
|
TestClass s = cast(TestClass)o;
|
||||||
if(s is null){return -1;}
|
if(s is null){return -1;}
|
||||||
|
@ -340,7 +340,7 @@ class TestClass
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
override string toString()
|
override string toString() @safe
|
||||||
{
|
{
|
||||||
return format("TestClass(", x, ", ", y, ", ", z, ")");
|
return format("TestClass(", x, ", ", y, ", ", z, ")");
|
||||||
}
|
}
|
||||||
|
@ -353,19 +353,19 @@ struct TestStruct
|
||||||
|
|
||||||
//Any D:YAML type must have a custom opCmp operator.
|
//Any D:YAML type must have a custom opCmp operator.
|
||||||
//This is used for ordering in mappings.
|
//This is used for ordering in mappings.
|
||||||
const int opCmp(ref const TestStruct s)
|
const int opCmp(ref const TestStruct s) @safe
|
||||||
{
|
{
|
||||||
return value - s.value;
|
return value - s.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///Constructor function for TestClass.
|
///Constructor function for TestClass.
|
||||||
TestClass constructClass(ref Node node)
|
TestClass constructClass(ref Node node) @safe
|
||||||
{
|
{
|
||||||
return new TestClass(node["x"].as!int, node["y"].as!int, node["z"].as!int);
|
return new TestClass(node["x"].as!int, node["y"].as!int, node["z"].as!int);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node representClass(ref Node node, Representer representer)
|
Node representClass(ref Node node, Representer representer) @safe
|
||||||
{
|
{
|
||||||
auto value = node.as!TestClass;
|
auto value = node.as!TestClass;
|
||||||
auto pairs = [Node.Pair("x", value.x),
|
auto pairs = [Node.Pair("x", value.x),
|
||||||
|
@ -377,13 +377,13 @@ Node representClass(ref Node node, Representer representer)
|
||||||
}
|
}
|
||||||
|
|
||||||
///Constructor function for TestStruct.
|
///Constructor function for TestStruct.
|
||||||
TestStruct constructStruct(ref Node node)
|
TestStruct constructStruct(ref Node node) @safe
|
||||||
{
|
{
|
||||||
return TestStruct(to!int(node.as!string));
|
return TestStruct(to!int(node.as!string));
|
||||||
}
|
}
|
||||||
|
|
||||||
///Representer function for TestStruct.
|
///Representer function for TestStruct.
|
||||||
Node representStruct(ref Node node, Representer representer)
|
Node representStruct(ref Node node, Representer representer) @safe
|
||||||
{
|
{
|
||||||
string[] keys, values;
|
string[] keys, values;
|
||||||
auto value = node.as!TestStruct;
|
auto value = node.as!TestStruct;
|
||||||
|
@ -398,7 +398,7 @@ Node representStruct(ref Node node, Representer representer)
|
||||||
* codeDummy = Dummy .code filename, used to determine that
|
* codeDummy = Dummy .code filename, used to determine that
|
||||||
* .data file with the same name should be used in this test.
|
* .data file with the same name should be used in this test.
|
||||||
*/
|
*/
|
||||||
void testConstructor(bool verbose, string dataFilename, string codeDummy)
|
void testConstructor(bool verbose, string dataFilename, string codeDummy) @safe
|
||||||
{
|
{
|
||||||
string base = dataFilename.baseName.stripExtension;
|
string base = dataFilename.baseName.stripExtension;
|
||||||
enforce((base in expected) !is null,
|
enforce((base in expected) !is null,
|
||||||
|
@ -436,7 +436,7 @@ void testConstructor(bool verbose, string dataFilename, string codeDummy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Constructor unittest");
|
writeln("D:YAML Constructor unittest");
|
||||||
run("testConstructor", &testConstructor, ["data", "code"]);
|
run("testConstructor", &testConstructor, ["data", "code"]);
|
||||||
|
|
|
@ -28,7 +28,7 @@ import dyaml.token;
|
||||||
/// events2 = Second event array to compare.
|
/// events2 = Second event array to compare.
|
||||||
///
|
///
|
||||||
/// Returns: true if the events are equivalent, false otherwise.
|
/// Returns: true if the events are equivalent, false otherwise.
|
||||||
bool compareEvents(Event[] events1, Event[] events2)
|
bool compareEvents(Event[] events1, Event[] events2) @system
|
||||||
{
|
{
|
||||||
if(events1.length != events2.length){return false;}
|
if(events1.length != events2.length){return false;}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ bool compareEvents(Event[] events1, Event[] events2)
|
||||||
/// dataFilename = YAML file to parse.
|
/// dataFilename = YAML file to parse.
|
||||||
/// canonicalFilename = Canonical YAML file used as dummy to determine
|
/// canonicalFilename = Canonical YAML file used as dummy to determine
|
||||||
/// which data files to load.
|
/// which data files to load.
|
||||||
void testEmitterOnData(bool verbose, string dataFilename, string canonicalFilename)
|
void testEmitterOnData(bool verbose, string dataFilename, string canonicalFilename) @system
|
||||||
{
|
{
|
||||||
//Must exist due to Anchor, Tags reference counts.
|
//Must exist due to Anchor, Tags reference counts.
|
||||||
auto loader = Loader(dataFilename);
|
auto loader = Loader(dataFilename);
|
||||||
|
@ -108,7 +108,7 @@ void testEmitterOnData(bool verbose, string dataFilename, string canonicalFilena
|
||||||
///
|
///
|
||||||
/// Params: verbose = Print verbose output?
|
/// Params: verbose = Print verbose output?
|
||||||
/// canonicalFilename = Canonical YAML file to parse.
|
/// canonicalFilename = Canonical YAML file to parse.
|
||||||
void testEmitterOnCanonical(bool verbose, string canonicalFilename)
|
void testEmitterOnCanonical(bool verbose, string canonicalFilename) @system
|
||||||
{
|
{
|
||||||
//Must exist due to Anchor, Tags reference counts.
|
//Must exist due to Anchor, Tags reference counts.
|
||||||
auto loader = Loader(canonicalFilename);
|
auto loader = Loader(canonicalFilename);
|
||||||
|
@ -141,7 +141,7 @@ void testEmitterOnCanonical(bool verbose, string canonicalFilename)
|
||||||
/// dataFilename = YAML file to parse.
|
/// dataFilename = YAML file to parse.
|
||||||
/// canonicalFilename = Canonical YAML file used as dummy to determine
|
/// canonicalFilename = Canonical YAML file used as dummy to determine
|
||||||
/// which data files to load.
|
/// which data files to load.
|
||||||
void testEmitterStyles(bool verbose, string dataFilename, string canonicalFilename)
|
void testEmitterStyles(bool verbose, string dataFilename, string canonicalFilename) @system
|
||||||
{
|
{
|
||||||
foreach(filename; [dataFilename, canonicalFilename])
|
foreach(filename; [dataFilename, canonicalFilename])
|
||||||
{
|
{
|
||||||
|
@ -194,7 +194,7 @@ void testEmitterStyles(bool verbose, string dataFilename, string canonicalFilena
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@system unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Emitter unittest");
|
writeln("D:YAML Emitter unittest");
|
||||||
run("testEmitterOnData", &testEmitterOnData, ["data", "canonical"]);
|
run("testEmitterOnData", &testEmitterOnData, ["data", "canonical"]);
|
||||||
|
|
|
@ -19,7 +19,7 @@ import dyaml.test.common;
|
||||||
///
|
///
|
||||||
/// Params: verbose = Print verbose output?
|
/// Params: verbose = Print verbose output?
|
||||||
/// errorFilename = File name to read from.
|
/// errorFilename = File name to read from.
|
||||||
void testLoaderError(bool verbose, string errorFilename)
|
void testLoaderError(bool verbose, string errorFilename) @safe
|
||||||
{
|
{
|
||||||
auto buffer = std.file.read(errorFilename);
|
auto buffer = std.file.read(errorFilename);
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ void testLoaderError(bool verbose, string errorFilename)
|
||||||
try { nodes = Loader(buffer).loadAll(); }
|
try { nodes = Loader(buffer).loadAll(); }
|
||||||
catch(YAMLException e)
|
catch(YAMLException e)
|
||||||
{
|
{
|
||||||
if(verbose) { writeln(typeid(e).toString(), "\n", e); }
|
printException(e, verbose);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(false, "Expected an exception");
|
assert(false, "Expected an exception");
|
||||||
|
@ -37,7 +37,7 @@ void testLoaderError(bool verbose, string errorFilename)
|
||||||
///
|
///
|
||||||
/// Params: verbose = Print verbose output?
|
/// Params: verbose = Print verbose output?
|
||||||
/// errorFilename = File name to read from.
|
/// errorFilename = File name to read from.
|
||||||
void testLoaderErrorString(bool verbose, string errorFilename)
|
void testLoaderErrorString(bool verbose, string errorFilename) @safe
|
||||||
{
|
{
|
||||||
// Load file to a buffer, then pass that to the YAML loader.
|
// Load file to a buffer, then pass that to the YAML loader.
|
||||||
auto buffer = std.file.read(errorFilename);
|
auto buffer = std.file.read(errorFilename);
|
||||||
|
@ -48,7 +48,7 @@ void testLoaderErrorString(bool verbose, string errorFilename)
|
||||||
}
|
}
|
||||||
catch(YAMLException e)
|
catch(YAMLException e)
|
||||||
{
|
{
|
||||||
if(verbose) { writeln(typeid(e).toString(), "\n", e); }
|
printException(e, verbose);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(false, "Expected an exception");
|
assert(false, "Expected an exception");
|
||||||
|
@ -58,12 +58,12 @@ void testLoaderErrorString(bool verbose, string errorFilename)
|
||||||
///
|
///
|
||||||
/// Params: verbose = Print verbose output?
|
/// Params: verbose = Print verbose output?
|
||||||
/// errorFilename = File name to read from.
|
/// errorFilename = File name to read from.
|
||||||
void testLoaderErrorFilename(bool verbose, string errorFilename)
|
void testLoaderErrorFilename(bool verbose, string errorFilename) @safe
|
||||||
{
|
{
|
||||||
try { auto nodes = Loader(errorFilename).loadAll(); }
|
try { auto nodes = Loader(errorFilename).loadAll(); }
|
||||||
catch(YAMLException e)
|
catch(YAMLException e)
|
||||||
{
|
{
|
||||||
if(verbose) { writeln(typeid(e).toString(), "\n", e); }
|
printException(e, verbose);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(false, "testLoaderErrorSingle(" ~ verbose.to!string ~
|
assert(false, "testLoaderErrorSingle(" ~ verbose.to!string ~
|
||||||
|
@ -74,19 +74,18 @@ void testLoaderErrorFilename(bool verbose, string errorFilename)
|
||||||
///
|
///
|
||||||
/// Params: verbose = Print verbose output?
|
/// Params: verbose = Print verbose output?
|
||||||
/// errorFilename = File name to read from.
|
/// errorFilename = File name to read from.
|
||||||
void testLoaderErrorSingle(bool verbose, string errorFilename)
|
void testLoaderErrorSingle(bool verbose, string errorFilename) @safe
|
||||||
{
|
{
|
||||||
try { auto nodes = Loader(errorFilename).load(); }
|
try { auto nodes = Loader(errorFilename).load(); }
|
||||||
catch(YAMLException e)
|
catch(YAMLException e)
|
||||||
{
|
{
|
||||||
if(verbose) { writeln(typeid(e).toString(), "\n", e); }
|
printException(e, verbose);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(false, "Expected an exception");
|
assert(false, "Expected an exception");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@safe unittest
|
||||||
unittest
|
|
||||||
{
|
{
|
||||||
writeln("D:YAML Errors unittest");
|
writeln("D:YAML Errors unittest");
|
||||||
run("testLoaderError", &testLoaderError, ["loader-error"]);
|
run("testLoaderError", &testLoaderError, ["loader-error"]);
|
||||||
|
|
|
@ -25,10 +25,10 @@ alias std.system.endian endian;
|
||||||
/// Params: wrong = Get the incorrect BOM for this system.
|
/// Params: wrong = Get the incorrect BOM for this system.
|
||||||
///
|
///
|
||||||
/// Returns: UTF-16 byte order mark.
|
/// Returns: UTF-16 byte order mark.
|
||||||
wchar bom16(bool wrong = false) pure
|
wchar bom16(bool wrong = false) pure @safe
|
||||||
{
|
{
|
||||||
wchar little = *(cast(wchar*)ByteOrderMarks[BOM.UTF16LE]);
|
wchar little = '\uFEFF';
|
||||||
wchar big = *(cast(wchar*)ByteOrderMarks[BOM.UTF16BE]);
|
wchar big = '\uFFFE';
|
||||||
if(!wrong){return endian == Endian.littleEndian ? little : big;}
|
if(!wrong){return endian == Endian.littleEndian ? little : big;}
|
||||||
return endian == Endian.littleEndian ? big : little;
|
return endian == Endian.littleEndian ? big : little;
|
||||||
}
|
}
|
||||||
|
@ -38,10 +38,10 @@ wchar bom16(bool wrong = false) pure
|
||||||
/// Params: wrong = Get the incorrect BOM for this system.
|
/// Params: wrong = Get the incorrect BOM for this system.
|
||||||
///
|
///
|
||||||
/// Returns: UTF-32 byte order mark.
|
/// Returns: UTF-32 byte order mark.
|
||||||
dchar bom32(bool wrong = false) pure
|
dchar bom32(bool wrong = false) pure @safe
|
||||||
{
|
{
|
||||||
dchar little = *(cast(dchar*)ByteOrderMarks[BOM.UTF32LE]);
|
dchar little = '\uFEFF';
|
||||||
dchar big = *(cast(dchar*)ByteOrderMarks[BOM.UTF32BE]);
|
dchar big = '\uFFFE';
|
||||||
if(!wrong){return endian == Endian.littleEndian ? little : big;}
|
if(!wrong){return endian == Endian.littleEndian ? little : big;}
|
||||||
return endian == Endian.littleEndian ? big : little;
|
return endian == Endian.littleEndian ? big : little;
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ dchar bom32(bool wrong = false) pure
|
||||||
///
|
///
|
||||||
/// Params: verbose = Print verbose output?
|
/// Params: verbose = Print verbose output?
|
||||||
/// unicodeFilename = File name to read from.
|
/// unicodeFilename = File name to read from.
|
||||||
void testUnicodeInput(bool verbose, string unicodeFilename)
|
void testUnicodeInput(bool verbose, string unicodeFilename) @safe
|
||||||
{
|
{
|
||||||
string data = readText(unicodeFilename);
|
string data = readText(unicodeFilename);
|
||||||
string expected = data.split().join(" ");
|
string expected = data.split().join(" ");
|
||||||
|
@ -70,7 +70,7 @@ void testUnicodeInput(bool verbose, string unicodeFilename)
|
||||||
///
|
///
|
||||||
/// Params: verbose = Print verbose output?
|
/// Params: verbose = Print verbose output?
|
||||||
/// unicodeFilename = File name to read from.
|
/// unicodeFilename = File name to read from.
|
||||||
void testUnicodeInputErrors(bool verbose, string unicodeFilename)
|
void testUnicodeInputErrors(bool verbose, string unicodeFilename) @safe
|
||||||
{
|
{
|
||||||
string data = readText(unicodeFilename);
|
string data = readText(unicodeFilename);
|
||||||
foreach(buffer; [cast(void[])(data.to!(wchar[])),
|
foreach(buffer; [cast(void[])(data.to!(wchar[])),
|
||||||
|
@ -81,7 +81,7 @@ void testUnicodeInputErrors(bool verbose, string unicodeFilename)
|
||||||
try { Loader(buffer).load(); }
|
try { Loader(buffer).load(); }
|
||||||
catch(YAMLException e)
|
catch(YAMLException e)
|
||||||
{
|
{
|
||||||
if(verbose) { writeln(typeid(e).toString(), "\n", e); }
|
printException(e, verbose);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
assert(false, "Expected an exception");
|
assert(false, "Expected an exception");
|
||||||
|
@ -89,7 +89,7 @@ void testUnicodeInputErrors(bool verbose, string unicodeFilename)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML I/O unittest");
|
writeln("D:YAML I/O unittest");
|
||||||
run("testUnicodeInput", &testUnicodeInput, ["unicode"]);
|
run("testUnicodeInput", &testUnicodeInput, ["unicode"]);
|
||||||
|
|
|
@ -18,7 +18,7 @@ import dyaml.reader;
|
||||||
//
|
//
|
||||||
// Params: verbose = Print verbose output?
|
// Params: verbose = Print verbose output?
|
||||||
// data = Stream to read.
|
// data = Stream to read.
|
||||||
void runReader(const bool verbose, void[] fileData)
|
void runReader(const bool verbose, ubyte[] fileData) @safe
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -27,7 +27,7 @@ void runReader(const bool verbose, void[] fileData)
|
||||||
}
|
}
|
||||||
catch(ReaderException e)
|
catch(ReaderException e)
|
||||||
{
|
{
|
||||||
if(verbose) { writeln(typeid(e).toString(), "\n", e); }
|
printException(e, verbose);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(false, "Expected an exception");
|
assert(false, "Expected an exception");
|
||||||
|
@ -38,13 +38,13 @@ void runReader(const bool verbose, void[] fileData)
|
||||||
///
|
///
|
||||||
/// Params: verbose = Print verbose output?
|
/// Params: verbose = Print verbose output?
|
||||||
/// errorFilename = File name to read from.
|
/// errorFilename = File name to read from.
|
||||||
void testStreamError(bool verbose, string errorFilename)
|
void testStreamError(bool verbose, string errorFilename) @trusted
|
||||||
{
|
{
|
||||||
import std.file;
|
import std.file;
|
||||||
runReader(verbose, std.file.read(errorFilename));
|
runReader(verbose, cast(ubyte[])std.file.read(errorFilename));
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Reader unittest");
|
writeln("D:YAML Reader unittest");
|
||||||
run("testStreamError", &testStreamError, ["stream-error"]);
|
run("testStreamError", &testStreamError, ["stream-error"]);
|
||||||
|
|
|
@ -24,7 +24,7 @@ import dyaml.test.constructor;
|
||||||
/// codeFilename = File name to determine test case from.
|
/// codeFilename = File name to determine test case from.
|
||||||
/// Nothing is read from this file, it only exists
|
/// Nothing is read from this file, it only exists
|
||||||
/// to specify that we need a matching unittest.
|
/// to specify that we need a matching unittest.
|
||||||
void testRepresenterTypes(bool verbose, string codeFilename)
|
void testRepresenterTypes(bool verbose, string codeFilename) @trusted
|
||||||
{
|
{
|
||||||
string baseName = codeFilename.baseName.stripExtension;
|
string baseName = codeFilename.baseName.stripExtension;
|
||||||
enforce((baseName in dyaml.test.constructor.expected) !is null,
|
enforce((baseName in dyaml.test.constructor.expected) !is null,
|
||||||
|
@ -77,7 +77,7 @@ void testRepresenterTypes(bool verbose, string codeFilename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Representer unittest");
|
writeln("D:YAML Representer unittest");
|
||||||
run("testRepresenterTypes", &testRepresenterTypes, ["code"]);
|
run("testRepresenterTypes", &testRepresenterTypes, ["code"]);
|
||||||
|
|
|
@ -23,7 +23,7 @@ import dyaml.test.common;
|
||||||
* dataFilename = File with unittest data.
|
* dataFilename = File with unittest data.
|
||||||
* detectFilename = Dummy filename used to specify which data filenames to use.
|
* detectFilename = Dummy filename used to specify which data filenames to use.
|
||||||
*/
|
*/
|
||||||
void testImplicitResolver(bool verbose, string dataFilename, string detectFilename)
|
void testImplicitResolver(bool verbose, string dataFilename, string detectFilename) @safe
|
||||||
{
|
{
|
||||||
string correctTag;
|
string correctTag;
|
||||||
Node node;
|
Node node;
|
||||||
|
@ -48,7 +48,7 @@ void testImplicitResolver(bool verbose, string dataFilename, string detectFilena
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML Resolver unittest");
|
writeln("D:YAML Resolver unittest");
|
||||||
run("testImplicitResolver", &testImplicitResolver, ["data", "detect"]);
|
run("testImplicitResolver", &testImplicitResolver, ["data", "detect"]);
|
||||||
|
|
|
@ -24,7 +24,7 @@ import dyaml.token;
|
||||||
* dataFilename = File to scan.
|
* dataFilename = File to scan.
|
||||||
* tokensFilename = File containing expected tokens.
|
* tokensFilename = File containing expected tokens.
|
||||||
*/
|
*/
|
||||||
void testTokens(bool verbose, string dataFilename, string tokensFilename)
|
void testTokens(bool verbose, string dataFilename, string tokensFilename) @safe
|
||||||
{
|
{
|
||||||
//representations of YAML tokens in tokens file.
|
//representations of YAML tokens in tokens file.
|
||||||
auto replace = [TokenID.Directive : "%" ,
|
auto replace = [TokenID.Directive : "%" ,
|
||||||
|
@ -72,7 +72,7 @@ void testTokens(bool verbose, string dataFilename, string tokensFilename)
|
||||||
* dataFilename = File to scan.
|
* dataFilename = File to scan.
|
||||||
* canonicalFilename = Another file to scan, in canonical YAML format.
|
* canonicalFilename = Another file to scan, in canonical YAML format.
|
||||||
*/
|
*/
|
||||||
void testScanner(bool verbose, string dataFilename, string canonicalFilename)
|
void testScanner(bool verbose, string dataFilename, string canonicalFilename) @safe
|
||||||
{
|
{
|
||||||
foreach(filename; [dataFilename, canonicalFilename])
|
foreach(filename; [dataFilename, canonicalFilename])
|
||||||
{
|
{
|
||||||
|
@ -86,7 +86,7 @@ void testScanner(bool verbose, string dataFilename, string canonicalFilename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
writeln("D:YAML tokens unittest");
|
writeln("D:YAML tokens unittest");
|
||||||
run("testTokens", &testTokens, ["data", "tokens"]);
|
run("testTokens", &testTokens, ["data", "tokens"]);
|
||||||
|
|
|
@ -97,16 +97,14 @@ struct Token
|
||||||
static assert(Token.sizeof <= 32, "Token has unexpected size");
|
static assert(Token.sizeof <= 32, "Token has unexpected size");
|
||||||
|
|
||||||
|
|
||||||
@safe pure nothrow @nogc:
|
|
||||||
|
|
||||||
/// Construct a directive token.
|
/// Construct a directive token.
|
||||||
///
|
///
|
||||||
/// Params: start = Start position of the token.
|
/// Params: start = Start position of the token.
|
||||||
/// end = End position of the token.
|
/// end = End position of the token.
|
||||||
/// value = Value of the token.
|
/// value = Value of the token.
|
||||||
/// directive = Directive type (YAML or TAG in YAML 1.1).
|
/// directive = Directive type (YAML or TAG in YAML 1.1).
|
||||||
Token directiveToken(const Mark start, const Mark end, char[] value,
|
Token directiveToken(const Mark start, const Mark end, char[] value,
|
||||||
DirectiveType directive, const uint nameEnd)
|
DirectiveType directive, const uint nameEnd) @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
return Token(value, start, end, TokenID.Directive, ScalarStyle.init, Encoding.init,
|
return Token(value, start, end, TokenID.Directive, ScalarStyle.init, Encoding.init,
|
||||||
directive, nameEnd);
|
directive, nameEnd);
|
||||||
|
@ -127,7 +125,7 @@ Token simpleToken(TokenID id)(const Mark start, const Mark end)
|
||||||
/// Params: start = Start position of the token.
|
/// Params: start = Start position of the token.
|
||||||
/// end = End position of the token.
|
/// end = End position of the token.
|
||||||
/// encoding = Encoding of the stream.
|
/// encoding = Encoding of the stream.
|
||||||
Token streamStartToken(const Mark start, const Mark end, const Encoding encoding)
|
Token streamStartToken(const Mark start, const Mark end, const Encoding encoding) @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
return Token(null, start, end, TokenID.StreamStart, ScalarStyle.Invalid, encoding);
|
return Token(null, start, end, TokenID.StreamStart, ScalarStyle.Invalid, encoding);
|
||||||
}
|
}
|
||||||
|
@ -168,7 +166,7 @@ alias simpleValueToken!(TokenID.Anchor) anchorToken;
|
||||||
/// end = End position of the token.
|
/// end = End position of the token.
|
||||||
/// value = Value of the token.
|
/// value = Value of the token.
|
||||||
/// style = Style of the token.
|
/// style = Style of the token.
|
||||||
Token scalarToken(const Mark start, const Mark end, char[] value, const ScalarStyle style)
|
Token scalarToken(const Mark start, const Mark end, char[] value, const ScalarStyle style) @safe pure nothrow @nogc
|
||||||
{
|
{
|
||||||
return Token(value, start, end, TokenID.Scalar, style);
|
return Token(value, start, end, TokenID.Scalar, style);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ auto decodeUTF(ubyte[] input, UTFEncoding encoding) @safe pure nothrow
|
||||||
// result = A Result struct to put decoded result and any error messages to.
|
// result = A Result struct to put decoded result and any error messages to.
|
||||||
//
|
//
|
||||||
// On error, result.errorMessage will be set.
|
// On error, result.errorMessage will be set.
|
||||||
static void decode(C)(C[] input, ref Result result) @safe pure nothrow
|
static void decode(C)(C[] input, ref Result result)
|
||||||
{
|
{
|
||||||
// End of part of input that contains complete characters that can be decoded.
|
// End of part of input that contains complete characters that can be decoded.
|
||||||
const size_t end = endOfLastUTFSequence(input);
|
const size_t end = endOfLastUTFSequence(input);
|
||||||
|
@ -107,7 +107,6 @@ auto decodeUTF(ubyte[] input, UTFEncoding encoding) @safe pure nothrow
|
||||||
|
|
||||||
// Determine the end of last UTF-8 or UTF-16 sequence in a raw buffer.
|
// Determine the end of last UTF-8 or UTF-16 sequence in a raw buffer.
|
||||||
size_t endOfLastUTFSequence(C)(const C[] buffer)
|
size_t endOfLastUTFSequence(C)(const C[] buffer)
|
||||||
@safe pure nothrow @nogc
|
|
||||||
{
|
{
|
||||||
static if(is(C == char))
|
static if(is(C == char))
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue