From 2c230751d22151410fe66b20e381cd56e5023f30 Mon Sep 17 00:00:00 2001 From: Ferdinand Majerech Date: Sun, 21 Aug 2011 00:07:32 +0200 Subject: [PATCH] Added support for null tag structs (used in parsing), using the Tag struct throughout the code. Event struct size decreased to 48 bytes. --- dyaml/composer.d | 8 ++++---- dyaml/constructor.d | 41 +++++++++++++++++++++++------------------ dyaml/event.d | 27 ++++++++++++++------------- dyaml/parser.d | 21 +++++++++++---------- dyaml/resolver.d | 31 ++++++++++++++++++++----------- dyaml/tag.d | 13 ++++++++++++- 6 files changed, 84 insertions(+), 57 deletions(-) diff --git a/dyaml/composer.d b/dyaml/composer.d index 70c363e..feb720c 100644 --- a/dyaml/composer.d +++ b/dyaml/composer.d @@ -17,10 +17,10 @@ import std.typecons; import dyaml.constructor; import dyaml.event; +import dyaml.exception; import dyaml.node; import dyaml.parser; import dyaml.resolver; -import dyaml.exception; package: @@ -204,7 +204,7 @@ final class Composer event.implicit); Node node = constructor_.node(event.startMark, event.endMark, tag, - event.value); + event.value); return node; } @@ -291,8 +291,8 @@ final class Composer Node composeMappingNode() { Event startEvent = parser_.getEvent(); - string tag = resolver_.resolve(NodeID.Mapping, startEvent.tag, null, - startEvent.implicit); + const tag = resolver_.resolve(NodeID.Mapping, startEvent.tag, null, + startEvent.implicit); Node.Pair[] children; Tuple!(Node, Mark)[] toMerge; diff --git a/dyaml/constructor.d b/dyaml/constructor.d index 943820f..331a49e 100644 --- a/dyaml/constructor.d +++ b/dyaml/constructor.d @@ -67,11 +67,11 @@ final class Constructor { private: ///Constructor functions from scalars. - Node.Value delegate(Mark, Mark, string) [string] fromScalar_; + Node.Value delegate(Mark, Mark, string) [Tag] fromScalar_; ///Constructor functions from sequences. - Node.Value delegate(Mark, Mark, Node[]) [string] fromSequence_; + Node.Value delegate(Mark, Mark, Node[]) [Tag] fromSequence_; ///Constructor functions from mappings. - Node.Value delegate (Mark, Mark, Node.Pair[])[string] fromMapping_; + Node.Value delegate (Mark, Mark, Node.Pair[])[Tag] fromMapping_; public: /** @@ -144,24 +144,26 @@ final class Constructor deleg = (Mark s, Mark e, U p){return Node.userValue(ctor(s,e,p));}; } - assert((tag in fromScalar_) is null && - (tag in fromSequence_) is null && - (tag in fromMapping_) is null, + const Tag t = Tag(tag); + + assert((t in fromScalar_) is null && + (t in fromSequence_) is null && + (t in fromMapping_) is null, "Constructor function for tag " ~ tag ~ " is already " "specified. Can't specify another one."); static if(is(U == string)) { - fromScalar_[tag] = deleg; + fromScalar_[t] = deleg; } else static if(is(U == Node[])) { - fromSequence_[tag] = deleg; + fromSequence_[t] = deleg; } 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. * end = End position of the node. + * tag = Tag (data type) of the node. * value = String value of the 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, new ConstructorException("Could not determine a constructor from " - "scalar for tag " ~ tag, start, end)); - return Node(fromScalar_[tag](start, end, value), start, Tag(tag)); + "scalar for tag " ~ tag.toString(), start, end)); + return Node(fromScalar_[tag](start, end, value), start, tag); } /* @@ -188,16 +191,17 @@ final class Constructor * * Params: start = Start position of the node. * end = End position of the node. + * tag = Tag (data type) of the node. * value = Sequence to construct node from. * * 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, new ConstructorException("Could not determine a constructor from " - "sequence for tag " ~ tag, start, end)); - return Node(fromSequence_[tag](start, end, value), start, Tag(tag)); + "sequence for tag " ~ tag.toString(), start, end)); + return Node(fromSequence_[tag](start, end, value), start, tag); } /* @@ -205,16 +209,17 @@ final class Constructor * * Params: start = Start position of the node. * end = End position of the node. + * tag = Tag (data type) of the node. * value = Mapping to construct node from. * * 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, new ConstructorException("Could not determine a constructor from " - "mapping for tag " ~ tag, start, end)); - return Node(fromMapping_[tag](start, end, value), start, Tag(tag)); + "mapping for tag " ~ tag.toString(), start, end)); + return Node(fromMapping_[tag](start, end, value), start, tag); } } diff --git a/dyaml/event.d b/dyaml/event.d index 5b5d98b..6169d71 100644 --- a/dyaml/event.d +++ b/dyaml/event.d @@ -14,9 +14,10 @@ import std.array; import std.conv; import std.typecons; -import dyaml.reader; -import dyaml.token; import dyaml.exception; +import dyaml.reader; +import dyaml.tag; +import dyaml.token; package: @@ -39,7 +40,7 @@ enum EventID : ubyte /** * YAML event produced by parser. * - * 64 bytes on 64-bit. + * 48 bytes on 64bit. */ immutable struct Event { @@ -49,10 +50,10 @@ immutable struct Event Mark endMark; ///Anchor of the event, if any. string anchor; - ///Tag of the event, if any. - string tag; ///Value of the event, if any. string value; + ///Tag of the event, if any. + Tag tag; ///Event type. EventID id; ///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 { - 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? */ 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 || 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. @@ -117,7 +118,7 @@ alias collectionStartEvent!(EventID.MappingStart) mappingStartEvent; */ 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); } @@ -130,7 +131,7 @@ Event documentStartEvent(Mark start, Mark end, bool explicit, string YAMLVersion */ 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); } @@ -145,9 +146,9 @@ Event documentEndEvent(Mark start, Mark end, bool explicit) * value = String value of the scalar. * 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 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); } diff --git a/dyaml/parser.d b/dyaml/parser.d index f9e00a5..8434bbc 100644 --- a/dyaml/parser.d +++ b/dyaml/parser.d @@ -16,9 +16,10 @@ import std.conv; import std.exception; import dyaml.event; +import dyaml.exception; import dyaml.scanner; import dyaml.token; -import dyaml.exception; +import dyaml.tag; package: @@ -447,7 +448,7 @@ final class Parser { state_ = &parseIndentlessSequenceEntry; return sequenceStartEvent(startMark, scanner_.peekToken().endMark, - anchor, tag, implicit); + anchor, Tag(tag), implicit); } if(scanner_.checkToken(TokenID.Scalar)) @@ -458,7 +459,7 @@ final class Parser //is never used after that - so we don't use it. implicit = (token.style == ScalarStyle.Plain && tag is null) || tag == "!"; state_ = popState(); - return scalarEvent(startMark, token.endMark, anchor, tag, + return scalarEvent(startMark, token.endMark, anchor, Tag(tag), implicit, token.value, token.style); } @@ -466,28 +467,28 @@ final class Parser { endMark = scanner_.peekToken().endMark; state_ = &parseFlowSequenceEntry!true; - return sequenceStartEvent(startMark, endMark, anchor, tag, implicit); + return sequenceStartEvent(startMark, endMark, anchor, Tag(tag), implicit); } if(scanner_.checkToken(TokenID.FlowMappingStart)) { endMark = scanner_.peekToken().endMark; state_ = &parseFlowMappingKey!true; - return mappingStartEvent(startMark, endMark, anchor, tag, implicit); + return mappingStartEvent(startMark, endMark, anchor, Tag(tag), implicit); } if(block && scanner_.checkToken(TokenID.BlockSequenceStart)) { endMark = scanner_.peekToken().endMark; state_ = &parseBlockSequenceEntry!true; - return sequenceStartEvent(startMark, endMark, anchor, tag, implicit); + return sequenceStartEvent(startMark, endMark, anchor, Tag(tag), implicit); } if(block && scanner_.checkToken(TokenID.BlockMappingStart)) { endMark = scanner_.peekToken().endMark; state_ = &parseBlockMappingKey!true; - return mappingStartEvent(startMark, endMark, anchor, tag, implicit); + return mappingStartEvent(startMark, endMark, anchor, Tag(tag), implicit); } 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. //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(); @@ -698,7 +699,7 @@ final class Parser { Token token = scanner_.peekToken(); 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)) { @@ -837,6 +838,6 @@ final class Parser { //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. - return scalarEvent(mark, mark, null, null, true, ""); + return scalarEvent(mark, mark, null, Tag(), true, ""); } } diff --git a/dyaml/resolver.d b/dyaml/resolver.d index 6f33547..2bfcab6 100644 --- a/dyaml/resolver.d +++ b/dyaml/resolver.d @@ -23,6 +23,7 @@ import std.utf; import dyaml.node; import dyaml.exception; +import dyaml.tag; /** @@ -34,18 +35,19 @@ final class Resolver { private: ///Default tag to use for scalars. - static string defaultScalarTag_ = "tag:yaml.org,2002:str"; + Tag defaultScalarTag_; ///Default tag to use for sequences. - static string defaultSequenceTag_ = "tag:yaml.org,2002:seq"; + Tag defaultSequenceTag_; ///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. * * Each tuple stores regular expression the scalar must match, * and tag to assign to it if it matches. */ - Tuple!(string, Regex!char)[][dchar] yamlImplicitResolvers_; + Tuple!(Tag, Regex!char)[][dchar] yamlImplicitResolvers_; public: /** @@ -58,6 +60,9 @@ final class Resolver */ 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();} } @@ -91,7 +96,7 @@ final class Resolver { yamlImplicitResolvers_[c] = []; } - yamlImplicitResolvers_[c] ~= tuple(tag, regexp); + yamlImplicitResolvers_[c] ~= tuple(Tag(tag), regexp); } } @@ -109,9 +114,9 @@ final class Resolver * * 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) { @@ -126,9 +131,11 @@ final class Resolver foreach(resolver; resolvers) { - tag = resolver[0]; - auto regexp = resolver[1]; - if(!(match(value, regexp).empty)){return tag;} + //If regexp matches, return tag. + if(!(match(value, resolver[1]).empty)) + { + return resolver[0]; + } } } return defaultScalarTag_; @@ -145,9 +152,11 @@ final class Resolver bool tagMatch(string tag, string[] values) { + Tag expected = Tag(tag); 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; } diff --git a/dyaml/tag.d b/dyaml/tag.d index c6b8f5a..781c18d 100644 --- a/dyaml/tag.d +++ b/dyaml/tag.d @@ -15,7 +15,7 @@ struct Tag { private: ///Index of the tag in tags_. - uint index_; + uint index_ = uint.max; /** * All known tags are in this array. @@ -29,6 +29,12 @@ struct Tag ///Construct a tag from a string representation. this(string tag) { + if(tag is null || tag == "") + { + index_ = uint.max; + return; + } + foreach(uint index, knownTag; tags_) { if(tag == knownTag) @@ -43,6 +49,8 @@ struct Tag ///Get string representation of the tag. string toString() const + in{assert(!isNull());} + body { return tags_[index_]; } @@ -52,4 +60,7 @@ struct Tag { return tag.index_ == index_; } + + ///Is this tag null (invalid)? + bool isNull() const {return index_ == uint.max;} }