Added Node constructors needed to create new nodes to emit.

This commit is contained in:
Ferdinand Majerech 2011-08-21 03:56:21 +02:00
parent 2c230751d2
commit b0f2ce201a
3 changed files with 191 additions and 15 deletions

View file

@ -183,7 +183,7 @@ final class Constructor
enforce((tag in fromScalar_) !is null, enforce((tag in fromScalar_) !is null,
new ConstructorException("Could not determine a constructor from " new ConstructorException("Could not determine a constructor from "
"scalar for tag " ~ tag.toString(), start, end)); "scalar for tag " ~ tag.toString(), start, end));
return Node(fromScalar_[tag](start, end, value), start, tag); return Node.rawNode(fromScalar_[tag](start, end, value), start, tag);
} }
/* /*
@ -201,7 +201,7 @@ final class Constructor
enforce((tag in fromSequence_) !is null, enforce((tag in fromSequence_) !is null,
new ConstructorException("Could not determine a constructor from " new ConstructorException("Could not determine a constructor from "
"sequence for tag " ~ tag.toString(), start, end)); "sequence for tag " ~ tag.toString(), start, end));
return Node(fromSequence_[tag](start, end, value), start, tag); return Node.rawNode(fromSequence_[tag](start, end, value), start, tag);
} }
/* /*
@ -219,7 +219,7 @@ final class Constructor
enforce((tag in fromMapping_) !is null, enforce((tag in fromMapping_) !is null,
new ConstructorException("Could not determine a constructor from " new ConstructorException("Could not determine a constructor from "
"mapping for tag " ~ tag.toString(), start, end)); "mapping for tag " ~ tag.toString(), start, end));
return Node(fromMapping_[tag](start, end, value), start, tag); return Node.rawNode(fromMapping_[tag](start, end, value), start, tag);
} }
} }
@ -565,9 +565,9 @@ unittest
Node[] pairs; Node[] pairs;
foreach(long i; 0 .. length) foreach(long i; 0 .. length)
{ {
auto pair = (i % 2) ? Pair(Node(Node.Value(to!string(i))), Node(Node.Value(i))) auto pair = (i % 2) ? Pair(Node.rawNode(Node.Value(to!string(i))), Node.rawNode(Node.Value(i)))
: Pair(Node(Node.Value(i)), Node(Node.Value(to!string(i)))); : Pair(Node.rawNode(Node.Value(i)), Node.rawNode(Node.Value(to!string(i))));
pairs ~= Node(Node.Value([pair])); pairs ~= Node.rawNode(Node.Value([pair]));
} }
return pairs; return pairs;
} }
@ -577,8 +577,8 @@ unittest
Node[] pairs; Node[] pairs;
foreach(long i; 0 .. length) foreach(long i; 0 .. length)
{ {
auto pair = Pair(Node(Node.Value(to!string(i))), Node(Node.Value(i))); auto pair = Pair(Node.rawNode(Node.Value(to!string(i))), Node.rawNode(Node.Value(i)));
pairs ~= Node(Node.Value([pair])); pairs ~= Node.rawNode(Node.Value([pair]));
} }
return pairs; return pairs;
} }
@ -630,7 +630,7 @@ unittest
Node.Pair[] pairs; Node.Pair[] pairs;
foreach(long i; 0 .. length) foreach(long i; 0 .. length)
{ {
pairs ~= Node.Pair(Node(Node.Value(to!string(i))), Node()); pairs ~= Node.Pair(Node.rawNode(Node.Value(to!string(i))), Node.rawNode(Node.Value(YAMLNull())));
} }
return pairs; return pairs;

View file

@ -143,6 +143,177 @@ struct Node
Tag tag_; Tag tag_;
public: public:
/**
* Construct a Node from a value.
*
* Any type except of Node can be stored in a Node, but default YAML
* types (integers, floats, strings, timestamp, etc.) will be stored
* more efficiently.
*
* Note that for any non-default types you store
* in a node, you need a Representer to represent them in YAML -
* otherwise emitting will fail.
*
* Params: value = Value to store in the node.
* tag = Tag override. If specified, the tag of the node
* when emitted will be this tag, regardless of
* what Representer determines. Can be used when a
* single D data type needs to use multiple YAML tags.
*/
this(T)(T value, string tag = null) if (!isArray!T && !isAssociativeArray!T)
{
tag_ = Tag(tag);
//No copyconstruction.
static if(is(T == Node))
{
static assert(false);
}
//We can easily convert ints, floats, strings.
else static if(isIntegral!T)
{
value_ = Value(cast(long) value);
}
else static if(isFloatingPoint!T)
{
value_ = Value(cast(real) value);
}
else static if(isSomeString!T)
{
value_ = Value(to!string(value));
}
//Directly supported type.
else static if(Value.allowed!T)
{
value_ = Value(value);
}
//User defined type.
else
{
value_ = userValue(value);
}
}
/**
* Construct a node from an array_.
*
* If array is an array_ of nodes or node pairs, it is stored in the
* node directly. Otherwise, every value in the array is converted to a
* node, and those nodes are stored.
*
* Params: array = Values to store in the node.
* tag = Tag override. If specified, the tag of the node
* when emitted will be this tag, regardless of
* what Representer determines. Can be used when a
* single D data type needs to use multiple YAML tags.
* In particular, this can be used to differentiate
* between YAML sequences (!!seq) and sets (!!set),
* which both are internally represented as an array_
* of nodes.
*/
this(T)(T[] array, string tag = null)
{
tag_ = Tag(tag);
static if(is(T == Node) || is(T == Node.Pair))
{
value_ = Value(array);
}
else
{
Node[] nodes;
foreach(ref value; array)
{
nodes ~= Node(value);
}
value_ = Value(nodes);
}
}
/**
* Construct a node from an associative array_.
*
* If keys and/or values of array are nodes, they are copied to the node
* directly. Otherwise they are converted to nodes and then stored.
*
* Params: array = Values to store in the node.
* tag = Tag override. If specified, the tag of the node
* when emitted will be this tag, regardless of
* what Representer determines. Can be used when a
* single D data type needs to use multiple YAML tags.
* In particular, this can be used to differentiate
* between YAML unordered maps, (!!map) ordered maps,
* (!!omap) and pairs (!!pairs), which are all
* internally represented as an array_ of node pairs.
*/
this(K, V)(V[K] array, string tag = null)
{
tag_ = Tag(tag);
Node.Pair[] pairs;
Node.Pair pair;
foreach(ref key, ref value; array)
{
static if(is(K == Node)){pair.key = key;}
else{pair.key = Node(key);}
static if(is(V == Node)){pair.value = value;}
else{pair.value = Node(value);}
pairs ~= pair;
}
value_ = Value(pairs);
}
/**
* Construct a node from arrays of keys_ and values_.
*
* Constructs a mapping node with key-value pairs from
* keys and values, keeping their order. Useful when order
* is important (ordered maps, pairs).
*
* keys and values must have equal length.
*
* If keys_ and/or values_ of are nodes, they are copied to the node
* directly. Otherwise they are converted to nodes and then stored.
*
* Params: keys = Keys of the mapping, from first to last pair.
* values = Values of the mapping, from first to last pair.
* tag = Tag override. If specified, the tag of the node
* when emitted will be this tag, regardless of
* what Representer determines. Can be used when a
* single D data type needs to use multiple YAML tags.
* In particular, this can be used to differentiate
* between YAML unordered maps, (!!map) ordered maps,
* (!!omap) and pairs (!!pairs), which are all
* internally represented as an array_ of node pairs.
*/
this(K, V)(K[] keys, V[] values, string tag = null)
in
{
assert(keys.length == values.length,
"Lengths of keys and values arrays to construct "
"a YAML node from don't match");
}
body
{
tag_ = Tag(tag);
Node.Pair[] pairs;
Node.Pair pair;
foreach(i; 0 .. keys.length)
{
static if(is(K == Node)){pair.key = keys[i];}
else{pair.key = Node(keys[i]);}
static if(is(V == Node)){pair.value = values[i];}
else{pair.value = Node(values[i]);}
pairs ~= pair;
}
value_ = Value(pairs);
}
///Is this node valid (initialized)? ///Is this node valid (initialized)?
@property bool isValid() const {return value_.hasValue;} @property bool isValid() const {return value_.hasValue;}
@ -573,12 +744,17 @@ struct Node
* Params: value = Value of the node. * Params: value = Value of the node.
* startMark = Start position of the node in file. * startMark = Start position of the node in file.
* tag = Tag of the node. * tag = Tag of the node.
*
* Returns: Constructed node.
*/ */
this(Value value, in Mark startMark = Mark(), in Tag tag = Tag("DUMMY_TAG")) static Node rawNode(Value value, in Mark startMark = Mark(), in Tag tag = Tag("DUMMY_TAG"))
{ {
value_ = value; Node node;
startMark_ = startMark; node.value_ = value;
tag_ = tag; node.startMark_ = startMark;
node.tag_ = tag;
return node;
} }
/* /*

View file

@ -54,8 +54,8 @@ static this()
///Construct a node with specified value. ///Construct a node with specified value.
Node node(T)(T value) Node node(T)(T value)
{ {
static if(Node.Value.allowed!T){return Node(Node.Value(value));} static if(Node.Value.allowed!T){return Node.rawNode(Node.Value(value));}
else{return Node(Node.userValue(value));} else{return Node.rawNode(Node.userValue(value));}
} }
///Construct a pair of nodes with specified values. ///Construct a pair of nodes with specified values.