Added support for null tag structs (used in parsing), using

the Tag struct throughout the code. Event struct size decreased
to 48 bytes.
This commit is contained in:
Ferdinand Majerech 2011-08-21 00:07:32 +02:00
parent dde7d2f64f
commit 2c230751d2
6 changed files with 84 additions and 57 deletions

View file

@ -17,10 +17,10 @@ import std.typecons;
import dyaml.constructor; import dyaml.constructor;
import dyaml.event; import dyaml.event;
import dyaml.exception;
import dyaml.node; import dyaml.node;
import dyaml.parser; import dyaml.parser;
import dyaml.resolver; import dyaml.resolver;
import dyaml.exception;
package: package:
@ -204,7 +204,7 @@ final class Composer
event.implicit); event.implicit);
Node node = constructor_.node(event.startMark, event.endMark, tag, Node node = constructor_.node(event.startMark, event.endMark, tag,
event.value); event.value);
return node; return node;
} }
@ -291,8 +291,8 @@ final class Composer
Node composeMappingNode() Node composeMappingNode()
{ {
Event startEvent = parser_.getEvent(); Event startEvent = parser_.getEvent();
string tag = resolver_.resolve(NodeID.Mapping, startEvent.tag, null, const tag = resolver_.resolve(NodeID.Mapping, startEvent.tag, null,
startEvent.implicit); startEvent.implicit);
Node.Pair[] children; Node.Pair[] children;
Tuple!(Node, Mark)[] toMerge; Tuple!(Node, Mark)[] toMerge;

View file

@ -67,11 +67,11 @@ final class Constructor
{ {
private: private:
///Constructor functions from scalars. ///Constructor functions from scalars.
Node.Value delegate(Mark, Mark, string) [string] fromScalar_; Node.Value delegate(Mark, Mark, string) [Tag] fromScalar_;
///Constructor functions from sequences. ///Constructor functions from sequences.
Node.Value delegate(Mark, Mark, Node[]) [string] fromSequence_; Node.Value delegate(Mark, Mark, Node[]) [Tag] fromSequence_;
///Constructor functions from mappings. ///Constructor functions from mappings.
Node.Value delegate (Mark, Mark, Node.Pair[])[string] fromMapping_; Node.Value delegate (Mark, Mark, Node.Pair[])[Tag] fromMapping_;
public: public:
/** /**
@ -144,24 +144,26 @@ final class Constructor
deleg = (Mark s, Mark e, U p){return Node.userValue(ctor(s,e,p));}; deleg = (Mark s, Mark e, U p){return Node.userValue(ctor(s,e,p));};
} }
assert((tag in fromScalar_) is null && const Tag t = Tag(tag);
(tag in fromSequence_) is null &&
(tag in fromMapping_) is null, assert((t in fromScalar_) is null &&
(t in fromSequence_) is null &&
(t in fromMapping_) is null,
"Constructor function for tag " ~ tag ~ " is already " "Constructor function for tag " ~ tag ~ " is already "
"specified. Can't specify another one."); "specified. Can't specify another one.");
static if(is(U == string)) static if(is(U == string))
{ {
fromScalar_[tag] = deleg; fromScalar_[t] = deleg;
} }
else static if(is(U == Node[])) else static if(is(U == Node[]))
{ {
fromSequence_[tag] = deleg; fromSequence_[t] = deleg;
} }
else static if(is(U == Node.Pair[])) else static if(is(U == Node.Pair[]))
{ {
fromMapping_[tag] = deleg; fromMapping_[t] = deleg;
} }
} }
@ -171,16 +173,17 @@ final class Constructor
* *
* Params: start = Start position of the node. * Params: start = Start position of the node.
* end = End position of the node. * end = End position of the node.
* tag = Tag (data type) of the node.
* value = String value of the node. * value = String value of the node.
* *
* Returns: Constructed node. * Returns: Constructed node.
*/ */
Node node(in Mark start, in Mark end, in string tag, string value) const Node node(in Mark start, in Mark end, in Tag tag, string value) const
{ {
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, start, end)); "scalar for tag " ~ tag.toString(), start, end));
return Node(fromScalar_[tag](start, end, value), start, Tag(tag)); return Node(fromScalar_[tag](start, end, value), start, tag);
} }
/* /*
@ -188,16 +191,17 @@ final class Constructor
* *
* Params: start = Start position of the node. * Params: start = Start position of the node.
* end = End position of the node. * end = End position of the node.
* tag = Tag (data type) of the node.
* value = Sequence to construct node from. * value = Sequence to construct node from.
* *
* Returns: Constructed node. * Returns: Constructed node.
*/ */
Node node(in Mark start, in Mark end, in string tag, Node[] value) const Node node(in Mark start, in Mark end, in Tag tag, Node[] value) const
{ {
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, start, end)); "sequence for tag " ~ tag.toString(), start, end));
return Node(fromSequence_[tag](start, end, value), start, Tag(tag)); return Node(fromSequence_[tag](start, end, value), start, tag);
} }
/* /*
@ -205,16 +209,17 @@ final class Constructor
* *
* Params: start = Start position of the node. * Params: start = Start position of the node.
* end = End position of the node. * end = End position of the node.
* tag = Tag (data type) of the node.
* value = Mapping to construct node from. * value = Mapping to construct node from.
* *
* Returns: Constructed node. * Returns: Constructed node.
*/ */
Node node(in Mark start, in Mark end, in string tag, Node.Pair[] value) const Node node(in Mark start, in Mark end, in Tag tag, Node.Pair[] value) const
{ {
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, start, end)); "mapping for tag " ~ tag.toString(), start, end));
return Node(fromMapping_[tag](start, end, value), start, Tag(tag)); return Node(fromMapping_[tag](start, end, value), start, tag);
} }
} }

View file

@ -14,9 +14,10 @@ import std.array;
import std.conv; import std.conv;
import std.typecons; import std.typecons;
import dyaml.reader;
import dyaml.token;
import dyaml.exception; import dyaml.exception;
import dyaml.reader;
import dyaml.tag;
import dyaml.token;
package: package:
@ -39,7 +40,7 @@ enum EventID : ubyte
/** /**
* YAML event produced by parser. * YAML event produced by parser.
* *
* 64 bytes on 64-bit. * 48 bytes on 64bit.
*/ */
immutable struct Event immutable struct Event
{ {
@ -49,10 +50,10 @@ immutable struct Event
Mark endMark; Mark endMark;
///Anchor of the event, if any. ///Anchor of the event, if any.
string anchor; string anchor;
///Tag of the event, if any.
string tag;
///Value of the event, if any. ///Value of the event, if any.
string value; string value;
///Tag of the event, if any.
Tag tag;
///Event type. ///Event type.
EventID id; EventID id;
///Style of scalar event, if this is a scalar event. ///Style of scalar event, if this is a scalar event.
@ -76,7 +77,7 @@ immutable struct Event
*/ */
Event event(EventID id)(in Mark start, in Mark end, in string anchor = null) pure Event event(EventID id)(in Mark start, in Mark end, in string anchor = null) pure
{ {
return Event(start, end, anchor, null, null, id); return Event(start, end, anchor, null, Tag(), id);
} }
/** /**
@ -89,11 +90,11 @@ Event event(EventID id)(in Mark start, in Mark end, in string anchor = null) pur
* implicit = Should the tag be implicitly resolved? * implicit = Should the tag be implicitly resolved?
*/ */
Event collectionStartEvent(EventID id)(in Mark start, in Mark end, in string anchor, Event collectionStartEvent(EventID id)(in Mark start, in Mark end, in string anchor,
in string tag, in bool implicit) pure in Tag tag, in bool implicit)
{ {
static assert(id == EventID.SequenceStart || id == EventID.SequenceEnd || static assert(id == EventID.SequenceStart || id == EventID.SequenceEnd ||
id == EventID.MappingStart || id == EventID.MappingEnd); id == EventID.MappingStart || id == EventID.MappingEnd);
return Event(start, end, anchor, tag, null, id, ScalarStyle.Invalid, implicit); return Event(start, end, anchor, null, tag, id, ScalarStyle.Invalid, implicit);
} }
///Aliases for simple events. ///Aliases for simple events.
@ -117,7 +118,7 @@ alias collectionStartEvent!(EventID.MappingStart) mappingStartEvent;
*/ */
Event documentStartEvent(Mark start, Mark end, bool explicit, string YAMLVersion) pure Event documentStartEvent(Mark start, Mark end, bool explicit, string YAMLVersion) pure
{ {
return Event(start, end, null, null, YAMLVersion, EventID.DocumentStart, return Event(start, end, null, YAMLVersion, Tag(), EventID.DocumentStart,
ScalarStyle.Invalid, explicit); ScalarStyle.Invalid, explicit);
} }
@ -130,7 +131,7 @@ Event documentStartEvent(Mark start, Mark end, bool explicit, string YAMLVersion
*/ */
Event documentEndEvent(Mark start, Mark end, bool explicit) Event documentEndEvent(Mark start, Mark end, bool explicit)
{ {
return Event(start, end, null, null, null, EventID.DocumentEnd, return Event(start, end, null, null, Tag(), EventID.DocumentEnd,
ScalarStyle.Invalid, explicit); ScalarStyle.Invalid, explicit);
} }
@ -145,9 +146,9 @@ Event documentEndEvent(Mark start, Mark end, bool explicit)
* value = String value of the scalar. * value = String value of the scalar.
* style = Scalar style. * style = Scalar style.
*/ */
Event scalarEvent(in Mark start, in Mark end, in string anchor, in string tag, Event scalarEvent(in Mark start, in Mark end, in string anchor, in Tag tag,
in bool implicit, in string value, in bool implicit, in string value,
in ScalarStyle style = ScalarStyle.Invalid) pure in ScalarStyle style = ScalarStyle.Invalid)
{ {
return Event(start, end, anchor, tag, value, EventID.Scalar, style, implicit); return Event(start, end, anchor, value, tag, EventID.Scalar, style, implicit);
} }

View file

@ -16,9 +16,10 @@ import std.conv;
import std.exception; import std.exception;
import dyaml.event; import dyaml.event;
import dyaml.exception;
import dyaml.scanner; import dyaml.scanner;
import dyaml.token; import dyaml.token;
import dyaml.exception; import dyaml.tag;
package: package:
@ -447,7 +448,7 @@ final class Parser
{ {
state_ = &parseIndentlessSequenceEntry; state_ = &parseIndentlessSequenceEntry;
return sequenceStartEvent(startMark, scanner_.peekToken().endMark, return sequenceStartEvent(startMark, scanner_.peekToken().endMark,
anchor, tag, implicit); anchor, Tag(tag), implicit);
} }
if(scanner_.checkToken(TokenID.Scalar)) if(scanner_.checkToken(TokenID.Scalar))
@ -458,7 +459,7 @@ final class Parser
//is never used after that - so we don't use it. //is never used after that - so we don't use it.
implicit = (token.style == ScalarStyle.Plain && tag is null) || tag == "!"; implicit = (token.style == ScalarStyle.Plain && tag is null) || tag == "!";
state_ = popState(); state_ = popState();
return scalarEvent(startMark, token.endMark, anchor, tag, return scalarEvent(startMark, token.endMark, anchor, Tag(tag),
implicit, token.value, token.style); implicit, token.value, token.style);
} }
@ -466,28 +467,28 @@ final class Parser
{ {
endMark = scanner_.peekToken().endMark; endMark = scanner_.peekToken().endMark;
state_ = &parseFlowSequenceEntry!true; state_ = &parseFlowSequenceEntry!true;
return sequenceStartEvent(startMark, endMark, anchor, tag, implicit); return sequenceStartEvent(startMark, endMark, anchor, Tag(tag), implicit);
} }
if(scanner_.checkToken(TokenID.FlowMappingStart)) if(scanner_.checkToken(TokenID.FlowMappingStart))
{ {
endMark = scanner_.peekToken().endMark; endMark = scanner_.peekToken().endMark;
state_ = &parseFlowMappingKey!true; state_ = &parseFlowMappingKey!true;
return mappingStartEvent(startMark, endMark, anchor, tag, implicit); return mappingStartEvent(startMark, endMark, anchor, Tag(tag), implicit);
} }
if(block && scanner_.checkToken(TokenID.BlockSequenceStart)) if(block && scanner_.checkToken(TokenID.BlockSequenceStart))
{ {
endMark = scanner_.peekToken().endMark; endMark = scanner_.peekToken().endMark;
state_ = &parseBlockSequenceEntry!true; state_ = &parseBlockSequenceEntry!true;
return sequenceStartEvent(startMark, endMark, anchor, tag, implicit); return sequenceStartEvent(startMark, endMark, anchor, Tag(tag), implicit);
} }
if(block && scanner_.checkToken(TokenID.BlockMappingStart)) if(block && scanner_.checkToken(TokenID.BlockMappingStart))
{ {
endMark = scanner_.peekToken().endMark; endMark = scanner_.peekToken().endMark;
state_ = &parseBlockMappingKey!true; state_ = &parseBlockMappingKey!true;
return mappingStartEvent(startMark, endMark, anchor, tag, implicit); return mappingStartEvent(startMark, endMark, anchor, Tag(tag), implicit);
} }
if(anchor != null || tag !is null) if(anchor != null || tag !is null)
@ -498,7 +499,7 @@ final class Parser
//but the second bool is never used after that - so we don't use it. //but the second bool is never used after that - so we don't use it.
//Empty scalars are allowed even if a tag or an anchor is specified. //Empty scalars are allowed even if a tag or an anchor is specified.
return scalarEvent(startMark, endMark, anchor, tag, implicit , ""); return scalarEvent(startMark, endMark, anchor, Tag(tag), implicit , "");
} }
Token token = scanner_.peekToken(); Token token = scanner_.peekToken();
@ -698,7 +699,7 @@ final class Parser
{ {
Token token = scanner_.peekToken(); Token token = scanner_.peekToken();
state_ = &parseFlowSequenceEntryMappingKey; state_ = &parseFlowSequenceEntryMappingKey;
return mappingStartEvent(token.startMark, token.endMark, null, null, true); return mappingStartEvent(token.startMark, token.endMark, null, Tag(), true);
} }
else if(!scanner_.checkToken(TokenID.FlowSequenceEnd)) else if(!scanner_.checkToken(TokenID.FlowSequenceEnd))
{ {
@ -837,6 +838,6 @@ final class Parser
{ {
//PyYAML uses a Tuple!(true, false) for the second last arg here, //PyYAML uses a Tuple!(true, false) for the second last arg here,
//but the second bool is never used after that - so we don't use it. //but the second bool is never used after that - so we don't use it.
return scalarEvent(mark, mark, null, null, true, ""); return scalarEvent(mark, mark, null, Tag(), true, "");
} }
} }

View file

@ -23,6 +23,7 @@ import std.utf;
import dyaml.node; import dyaml.node;
import dyaml.exception; import dyaml.exception;
import dyaml.tag;
/** /**
@ -34,18 +35,19 @@ final class Resolver
{ {
private: private:
///Default tag to use for scalars. ///Default tag to use for scalars.
static string defaultScalarTag_ = "tag:yaml.org,2002:str"; Tag defaultScalarTag_;
///Default tag to use for sequences. ///Default tag to use for sequences.
static string defaultSequenceTag_ = "tag:yaml.org,2002:seq"; Tag defaultSequenceTag_;
///Default tag to use for mappings. ///Default tag to use for mappings.
static string defaultMappingTag_ = "tag:yaml.org,2002:map"; Tag defaultMappingTag_;
/** /**
* Arrays of scalar resolver tuples indexed by starting character of a scalar. * Arrays of scalar resolver tuples indexed by starting character of a scalar.
* *
* Each tuple stores regular expression the scalar must match, * Each tuple stores regular expression the scalar must match,
* and tag to assign to it if it matches. * and tag to assign to it if it matches.
*/ */
Tuple!(string, Regex!char)[][dchar] yamlImplicitResolvers_; Tuple!(Tag, Regex!char)[][dchar] yamlImplicitResolvers_;
public: public:
/** /**
@ -58,6 +60,9 @@ final class Resolver
*/ */
this(in bool defaultImplicitResolvers = true) this(in bool defaultImplicitResolvers = true)
{ {
defaultScalarTag_ = Tag("tag:yaml.org,2002:str");
defaultSequenceTag_ = Tag("tag:yaml.org,2002:seq");
defaultMappingTag_ = Tag("tag:yaml.org,2002:map");
if(defaultImplicitResolvers){addImplicitResolvers();} if(defaultImplicitResolvers){addImplicitResolvers();}
} }
@ -91,7 +96,7 @@ final class Resolver
{ {
yamlImplicitResolvers_[c] = []; yamlImplicitResolvers_[c] = [];
} }
yamlImplicitResolvers_[c] ~= tuple(tag, regexp); yamlImplicitResolvers_[c] ~= tuple(Tag(tag), regexp);
} }
} }
@ -109,9 +114,9 @@ final class Resolver
* *
* Returns: Resolved tag. * Returns: Resolved tag.
*/ */
string resolve(NodeID kind, string tag, string value, in bool implicit) Tag resolve(NodeID kind, Tag tag, string value, in bool implicit)
{ {
if(tag !is null && tag != "!"){return tag;} if(!tag.isNull() && tag.toString() != "!"){return tag;}
if(kind == NodeID.Scalar) if(kind == NodeID.Scalar)
{ {
@ -126,9 +131,11 @@ final class Resolver
foreach(resolver; resolvers) foreach(resolver; resolvers)
{ {
tag = resolver[0]; //If regexp matches, return tag.
auto regexp = resolver[1]; if(!(match(value, resolver[1]).empty))
if(!(match(value, regexp).empty)){return tag;} {
return resolver[0];
}
} }
} }
return defaultScalarTag_; return defaultScalarTag_;
@ -145,9 +152,11 @@ final class Resolver
bool tagMatch(string tag, string[] values) bool tagMatch(string tag, string[] values)
{ {
Tag expected = Tag(tag);
foreach(value; values) foreach(value; values)
{ {
if(tag != resolver.resolve(NodeID.Scalar, null, value, true)) Tag resolved = resolver.resolve(NodeID.Scalar, Tag(), value, true);
if(expected != resolved)
{ {
return false; return false;
} }

View file

@ -15,7 +15,7 @@ struct Tag
{ {
private: private:
///Index of the tag in tags_. ///Index of the tag in tags_.
uint index_; uint index_ = uint.max;
/** /**
* All known tags are in this array. * All known tags are in this array.
@ -29,6 +29,12 @@ struct Tag
///Construct a tag from a string representation. ///Construct a tag from a string representation.
this(string tag) this(string tag)
{ {
if(tag is null || tag == "")
{
index_ = uint.max;
return;
}
foreach(uint index, knownTag; tags_) foreach(uint index, knownTag; tags_)
{ {
if(tag == knownTag) if(tag == knownTag)
@ -43,6 +49,8 @@ struct Tag
///Get string representation of the tag. ///Get string representation of the tag.
string toString() const string toString() const
in{assert(!isNull());}
body
{ {
return tags_[index_]; return tags_[index_];
} }
@ -52,4 +60,7 @@ struct Tag
{ {
return tag.index_ == index_; return tag.index_ == index_;
} }
///Is this tag null (invalid)?
bool isNull() const {return index_ == uint.max;}
} }