Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement YAML schemas #251

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/yaml_bench/yaml_bench.d
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ void main(string[] args) //@safe
{
// Instead of constructing a resolver/constructor with each Loader,
// construct them once to remove noise when profiling.
auto resolver = Resolver.withDefaultResolvers;
auto resolver = Resolver(DefaultSchema);

auto constructTime = stopWatch.peek();

Expand Down
67 changes: 34 additions & 33 deletions source/dyaml/composer.d
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,8 @@ class ComposerException : MarkedYAMLException
struct Composer
{
private:
///Parser providing YAML events.
Parser parser_;
///Resolver resolving tags (data types).
Resolver resolver_;
///Nodes associated with anchors. Used by YAML aliases.
Node[string] anchors_;

///Used to reduce allocations when creating pair arrays.
///
///We need one appender for each nesting level that involves
Expand All @@ -62,7 +57,13 @@ struct Composer
///part of the outer levels. Used as a stack.
Appender!(Node[])[] nodeAppenders_;

package:
///Parser providing YAML events.
Parser parser;
///Resolver resolving tags (data types).
Resolver resolver;
public:
@disable this();
/**
* Construct a composer.
*
Expand All @@ -71,8 +72,8 @@ struct Composer
*/
this(Parser parser, Resolver resolver) @safe
{
parser_ = parser;
resolver_ = resolver;
this.parser = parser;
this.resolver = resolver;
}

/**
Expand All @@ -83,17 +84,17 @@ struct Composer
bool checkNode() @safe
{
// If next event is stream start, skip it
parser_.skipOver!"a.id == b"(EventID.streamStart);
parser.skipOver!"a.id == b"(EventID.streamStart);

//True if there are more documents available.
return parser_.front.id != EventID.streamEnd;
return parser.front.id != EventID.streamEnd;
}

///Get a YAML document as a node (the root of the document).
Node getNode() @safe
{
//Get the root node of the next document.
assert(parser_.front.id != EventID.streamEnd,
assert(parser.front.id != EventID.streamEnd,
"Trying to get a node from Composer when there is no node to " ~
"get. use checkNode() to determine if there is a node.");

Expand All @@ -104,7 +105,7 @@ struct Composer

void skipExpected(const EventID id) @safe
{
const foundExpected = parser_.skipOver!"a.id == b"(id);
const foundExpected = parser.skipOver!"a.id == b"(id);
assert(foundExpected, text("Expected ", id, " not found."));
}
///Ensure that appenders for specified nesting levels exist.
Expand Down Expand Up @@ -144,10 +145,10 @@ struct Composer
/// nodeAppenderLevel = Current level of the node appender stack.
Node composeNode(const uint pairAppenderLevel, const uint nodeAppenderLevel) @safe
{
if(parser_.front.id == EventID.alias_)
if(parser.front.id == EventID.alias_)
{
const event = parser_.front;
parser_.popFront();
const event = parser.front;
parser.popFront();
const anchor = event.anchor;
enforce((anchor in anchors_) !is null,
new ComposerException("Found undefined alias: " ~ anchor,
Expand All @@ -163,7 +164,7 @@ struct Composer
return anchors_[anchor];
}

const event = parser_.front;
const event = parser.front;
const anchor = event.anchor;
if((anchor !is null) && (anchor in anchors_) !is null)
{
Expand All @@ -179,7 +180,7 @@ struct Composer
anchors_[anchor] = Node();
}

switch (parser_.front.id)
switch (parser.front.id)
{
case EventID.scalar:
result = composeScalarNode();
Expand All @@ -203,9 +204,9 @@ struct Composer
///Compose a scalar node.
Node composeScalarNode() @safe
{
const event = parser_.front;
parser_.popFront();
const tag = resolver_.resolve(NodeID.scalar, event.tag, event.value,
const event = parser.front;
parser.popFront();
const tag = resolver.resolve(NodeID.scalar, event.tag, event.value,
event.implicit);

Node node = constructNode(event.startMark, event.endMark, tag,
Expand All @@ -225,20 +226,20 @@ struct Composer
ensureAppendersExist(pairAppenderLevel, nodeAppenderLevel);
auto nodeAppender = &(nodeAppenders_[nodeAppenderLevel]);

const startEvent = parser_.front;
parser_.popFront();
const tag = resolver_.resolve(NodeID.sequence, startEvent.tag, null,
const startEvent = parser.front;
parser.popFront();
const tag = resolver.resolve(NodeID.sequence, startEvent.tag, null,
startEvent.implicit);

while(parser_.front.id != EventID.sequenceEnd)
while(parser.front.id != EventID.sequenceEnd)
{
nodeAppender.put(composeNode(pairAppenderLevel, nodeAppenderLevel + 1));
}

Node node = constructNode(startEvent.startMark, parser_.front.endMark,
Node node = constructNode(startEvent.startMark, parser.front.endMark,
tag, nodeAppender.data.dup);
node.collectionStyle = startEvent.collectionStyle;
parser_.popFront();
parser.popFront();
nodeAppender.clear();

return node;
Expand Down Expand Up @@ -329,22 +330,22 @@ struct Composer
@safe
{
ensureAppendersExist(pairAppenderLevel, nodeAppenderLevel);
const startEvent = parser_.front;
parser_.popFront();
const tag = resolver_.resolve(NodeID.mapping, startEvent.tag, null,
const startEvent = parser.front;
parser.popFront();
const tag = resolver.resolve(NodeID.mapping, startEvent.tag, null,
startEvent.implicit);
auto pairAppender = &(pairAppenders_[pairAppenderLevel]);

Tuple!(Node, Mark)[] toMerge;
while(parser_.front.id != EventID.mappingEnd)
while(parser.front.id != EventID.mappingEnd)
{
auto pair = Node.Pair(composeNode(pairAppenderLevel + 1, nodeAppenderLevel),
composeNode(pairAppenderLevel + 1, nodeAppenderLevel));

//Need to flatten and merge the node referred by YAMLMerge.
if(pair.key.type == NodeType.merge)
{
toMerge ~= tuple(pair.value, cast(Mark)parser_.front.endMark);
toMerge ~= tuple(pair.value, cast(Mark)parser.front.endMark);
}
//Not YAMLMerge, just add the pair.
else
Expand All @@ -362,12 +363,12 @@ struct Composer
.uniq!((x,y) => x.key == y.key)
.walkLength;
enforce(numUnique == pairAppender.data.length,
new ComposerException("Duplicate key found in mapping", parser_.front.startMark));
new ComposerException("Duplicate key found in mapping", parser.front.startMark));

Node node = constructNode(startEvent.startMark, parser_.front.endMark,
Node node = constructNode(startEvent.startMark, parser.front.endMark,
tag, pairAppender.data.dup);
node.collectionStyle = startEvent.collectionStyle;
parser_.popFront();
parser.popFront();

pairAppender.clear();
return node;
Expand Down
17 changes: 11 additions & 6 deletions source/dyaml/dumper.d
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import dyaml.linebreak;
import dyaml.node;
import dyaml.representer;
import dyaml.resolver;
import dyaml.schema;
import dyaml.serializer;
import dyaml.style;
import dyaml.tagdirective;
Expand All @@ -37,9 +38,11 @@ import dyaml.tagdirective;
*/
auto dumper()
{
auto dumper = Dumper();
dumper.resolver = Resolver.withDefaultResolvers;
return dumper;
return dumper(DefaultSchema);
}
auto dumper(Schema schema)
{
return Dumper(Resolver(schema));
}

struct Dumper
Expand Down Expand Up @@ -73,8 +76,10 @@ struct Dumper
// Default style for collection nodes. If style is $(D CollectionStyle.invalid), the _style is chosen automatically.
CollectionStyle defaultCollectionStyle = CollectionStyle.invalid;

@disable bool opEquals(ref Dumper);
@disable int opCmp(ref Dumper);
@disable this();
this(Resolver resolver) pure @safe{
this.resolver = resolver;
}

///Set indentation width. 2 by default. Must not be zero.
@property void indent(uint indent) pure @safe nothrow
Expand Down Expand Up @@ -195,7 +200,7 @@ struct Dumper
import std.regex : regex;
auto node = Node([1, 2, 3, 4, 5]);
auto dumper = dumper();
dumper.resolver.addImplicitResolver("!tag", regex("A.*"), "A");
dumper.resolver.addRule(SchemaRule("!tag", regex("A.*"), "A"));
dumper.dump(new Appender!string(), node);
}
/// Set default scalar style
Expand Down
25 changes: 11 additions & 14 deletions source/dyaml/loader.d
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import dyaml.parser;
import dyaml.reader;
import dyaml.resolver;
import dyaml.scanner;
import dyaml.schema;
import dyaml.token;


Expand All @@ -36,9 +37,9 @@ struct Loader
// Processes character data to YAML tokens.
Scanner scanner_;
// Processes tokens to YAML events.
Parser parser_;
// Resolves tags (data types).
Resolver resolver_;
//Parser parser_;
//
Composer composer_;
// Name of the input file or stream, used in error messages.
string name_ = "<unknown>";
// Are we done loading?
Expand Down Expand Up @@ -147,12 +148,12 @@ struct Loader
/// Ditto
private this(ubyte[] yamlData) @safe
{
resolver_ = Resolver.withDefaultResolvers;
auto resolver = Resolver(DefaultSchema);
try
{
auto reader_ = new Reader(yamlData);
scanner_ = Scanner(reader_);
parser_ = new Parser(scanner_);
composer_ = Composer(new Parser(scanner_), resolver);
}
catch(YAMLException e)
{
Expand All @@ -171,7 +172,7 @@ struct Loader
/// Specify custom Resolver to use.
auto ref resolver() pure @safe nothrow @nogc
{
return resolver_;
return composer_.resolver;
}

/** Load single YAML document.
Expand Down Expand Up @@ -213,20 +214,16 @@ struct Loader
*
* Reads the next document from the stream, if possible.
*/
void popFront() @safe
void popFront() @trusted
{
// Composer initialization is done here in case the constructor is
// modified, which is a pretty common case.
static Composer composer;
if (!rangeInitialized)
{
composer = Composer(parser_, resolver_);
rangeInitialized = true;
}
assert(!done_, "Loader.popFront called on empty range");
if (composer.checkNode())
if (composer_.checkNode())
{
currentNode = composer.getNode();
currentNode = composer_.getNode();
}
else
{
Expand Down Expand Up @@ -268,7 +265,7 @@ struct Loader
// Parse and return all events. Used for debugging.
auto parse() @safe
{
return parser_;
return composer_.parser;
}
}
/// Load single YAML document from a file:
Expand Down
1 change: 1 addition & 0 deletions source/dyaml/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ public import dyaml.exception;
public import dyaml.linebreak;
public import dyaml.loader;
public import dyaml.resolver;
public import dyaml.schema;
public import dyaml.style;
public import dyaml.node;
Loading