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:
parent
dde7d2f64f
commit
2c230751d2
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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, "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
13
dyaml/tag.d
13
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;}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue