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.event;
import dyaml.exception;
import dyaml.node;
import dyaml.parser;
import dyaml.resolver;
import dyaml.exception;
package:
@ -291,7 +291,7 @@ final class Composer
Node composeMappingNode()
{
Event startEvent = parser_.getEvent();
string tag = resolver_.resolve(NodeID.Mapping, startEvent.tag, null,
const tag = resolver_.resolve(NodeID.Mapping, startEvent.tag, null,
startEvent.implicit);
Node.Pair[] children;

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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, "");
}
}

View file

@ -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;
}

View file

@ -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;}
}