convert Resolver to struct (#229)
convert Resolver to struct merged-on-behalf-of: Basile-z <Basile-z@users.noreply.github.com>
This commit is contained in:
parent
fff8cead76
commit
8de1a45922
|
@ -12,12 +12,10 @@ int main(string[] args)
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto resolver = new Resolver;
|
|
||||||
resolver.addImplicitResolver("!color", regex("[0-9a-fA-F]{6}"),
|
|
||||||
"0123456789abcdefABCDEF");
|
|
||||||
|
|
||||||
auto loader = Loader.fromFile("input.yaml");
|
auto loader = Loader.fromFile("input.yaml");
|
||||||
loader.resolver = resolver;
|
loader.resolver.addImplicitResolver("!color", regex("[0-9a-fA-F]{6}"),
|
||||||
|
"0123456789abcdefABCDEF");
|
||||||
|
|
||||||
auto root = loader.load();
|
auto root = loader.load();
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ void main(string[] args) //@safe
|
||||||
{
|
{
|
||||||
// Instead of constructing a resolver/constructor with each Loader,
|
// Instead of constructing a resolver/constructor with each Loader,
|
||||||
// construct them once to remove noise when profiling.
|
// construct them once to remove noise when profiling.
|
||||||
auto resolver = new Resolver();
|
auto resolver = Resolver.withDefaultResolvers;
|
||||||
|
|
||||||
auto constructTime = stopWatch.peek();
|
auto constructTime = stopWatch.peek();
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ void main(string[] args) //@safe
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loader.resolver = resolver;
|
loader.resolver = resolver;
|
||||||
nodes = loader.array;
|
nodes = loader.array;
|
||||||
}
|
}
|
||||||
void runDumpBenchmark() @safe
|
void runDumpBenchmark() @safe
|
||||||
|
|
|
@ -79,7 +79,6 @@ struct Composer
|
||||||
pure @safe nothrow ~this()
|
pure @safe nothrow ~this()
|
||||||
{
|
{
|
||||||
parser_ = null;
|
parser_ = null;
|
||||||
resolver_ = null;
|
|
||||||
anchors_.destroy();
|
anchors_.destroy();
|
||||||
anchors_ = null;
|
anchors_ = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ struct Dumper(Range)
|
||||||
*/
|
*/
|
||||||
this(Range stream) @safe
|
this(Range stream) @safe
|
||||||
{
|
{
|
||||||
resolver_ = new Resolver();
|
resolver_ = Resolver.withDefaultResolvers;
|
||||||
stream_ = stream;
|
stream_ = stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,9 +110,9 @@ struct Dumper(Range)
|
||||||
}
|
}
|
||||||
|
|
||||||
///Specify custom Resolver to use.
|
///Specify custom Resolver to use.
|
||||||
@property void resolver(Resolver resolver) @safe
|
auto ref resolver() @safe
|
||||||
{
|
{
|
||||||
resolver_ = resolver;
|
return resolver_;
|
||||||
}
|
}
|
||||||
|
|
||||||
///Write scalars in _canonical form?
|
///Write scalars in _canonical form?
|
||||||
|
@ -290,10 +290,10 @@ struct Dumper(Range)
|
||||||
///Use a custom resolver to support custom data types and/or implicit tags
|
///Use a custom resolver to support custom data types and/or implicit tags
|
||||||
@safe unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
|
import std.regex : regex;
|
||||||
auto node = Node([1, 2, 3, 4, 5]);
|
auto node = Node([1, 2, 3, 4, 5]);
|
||||||
auto resolver = new Resolver();
|
|
||||||
auto dumper = dumper(new Appender!string());
|
auto dumper = dumper(new Appender!string());
|
||||||
dumper.resolver = resolver;
|
dumper.resolver.addImplicitResolver("!tag", regex("A.*"), "A");
|
||||||
dumper.dump(node);
|
dumper.dump(node);
|
||||||
}
|
}
|
||||||
/// Set default scalar style
|
/// Set default scalar style
|
||||||
|
|
|
@ -149,6 +149,7 @@ struct Loader
|
||||||
/// Ditto
|
/// Ditto
|
||||||
private this(ubyte[] yamlData) @safe
|
private this(ubyte[] yamlData) @safe
|
||||||
{
|
{
|
||||||
|
resolver_ = Resolver.withDefaultResolvers;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
reader_ = new Reader(yamlData);
|
reader_ = new Reader(yamlData);
|
||||||
|
@ -170,9 +171,9 @@ struct Loader
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify custom Resolver to use.
|
/// Specify custom Resolver to use.
|
||||||
void resolver(Resolver resolver) pure @safe nothrow @nogc
|
auto ref resolver() pure @safe nothrow @nogc
|
||||||
{
|
{
|
||||||
resolver_ = resolver;
|
return resolver_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Load single YAML document.
|
/** Load single YAML document.
|
||||||
|
@ -221,7 +222,6 @@ struct Loader
|
||||||
static Composer composer;
|
static Composer composer;
|
||||||
if (!rangeInitialized)
|
if (!rangeInitialized)
|
||||||
{
|
{
|
||||||
lazyInitConstructorResolver();
|
|
||||||
composer = Composer(parser_, resolver_);
|
composer = Composer(parser_, resolver_);
|
||||||
rangeInitialized = true;
|
rangeInitialized = true;
|
||||||
}
|
}
|
||||||
|
@ -290,13 +290,6 @@ struct Loader
|
||||||
{
|
{
|
||||||
return parser_;
|
return parser_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct default constructor/resolver if the user has not yet specified
|
|
||||||
// their own.
|
|
||||||
void lazyInitConstructorResolver() @safe
|
|
||||||
{
|
|
||||||
if(resolver_ is null) { resolver_ = new Resolver(); }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/// Load single YAML document from a file:
|
/// Load single YAML document from a file:
|
||||||
@safe unittest
|
@safe unittest
|
||||||
|
@ -394,7 +387,7 @@ struct Loader
|
||||||
writeln("Failed to read file 'example.yaml'");
|
writeln("Failed to read file 'example.yaml'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Use a custom constructor/resolver to support custom data types and/or implicit tags:
|
/// Use a custom resolver to support custom data types and/or implicit tags:
|
||||||
@safe unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
import std.file : write;
|
import std.file : write;
|
||||||
|
@ -404,11 +397,11 @@ struct Loader
|
||||||
"Hello world!\n"~
|
"Hello world!\n"~
|
||||||
"...\n"
|
"...\n"
|
||||||
);
|
);
|
||||||
auto resolver = new Resolver();
|
|
||||||
|
|
||||||
// Add constructor functions / resolver expressions here...
|
|
||||||
|
|
||||||
auto loader = Loader.fromFile("example.yaml");
|
auto loader = Loader.fromFile("example.yaml");
|
||||||
loader.resolver = resolver;
|
|
||||||
|
// Add resolver expressions here...
|
||||||
|
// loader.resolver.addImplicitResolver(...);
|
||||||
|
|
||||||
auto rootNode = loader.load();
|
auto rootNode = loader.load();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,53 @@ import dyaml.node;
|
||||||
import dyaml.exception;
|
import dyaml.exception;
|
||||||
|
|
||||||
|
|
||||||
|
static Tuple!(string, "tag", Regex!char, "regexp", string, "chars")[] regexes;
|
||||||
|
|
||||||
|
static this() @safe {
|
||||||
|
regexes ~= tuple!("tag", "regexp", "chars")("tag:yaml.org,2002:bool",
|
||||||
|
regex(r"^(?:yes|Yes|YES|no|No|NO|true|True|TRUE" ~
|
||||||
|
"|false|False|FALSE|on|On|ON|off|Off|OFF)$"),
|
||||||
|
"yYnNtTfFoO");
|
||||||
|
regexes ~= tuple!("tag", "regexp", "chars")("tag:yaml.org,2002:float",
|
||||||
|
regex(r"^(?:[-+]?([0-9][0-9_]*)\\.[0-9_]*" ~
|
||||||
|
"(?:[eE][-+][0-9]+)?|[-+]?(?:[0-9][0-9_]" ~
|
||||||
|
"*)?\\.[0-9_]+(?:[eE][-+][0-9]+)?|[-+]?" ~
|
||||||
|
"[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]" ~
|
||||||
|
"*|[-+]?\\.(?:inf|Inf|INF)|\\." ~
|
||||||
|
"(?:nan|NaN|NAN))$"),
|
||||||
|
"-+0123456789.");
|
||||||
|
regexes ~= tuple!("tag", "regexp", "chars")("tag:yaml.org,2002:int",
|
||||||
|
regex(r"^(?:[-+]?0b[0-1_]+" ~
|
||||||
|
"|[-+]?0[0-7_]+" ~
|
||||||
|
"|[-+]?(?:0|[1-9][0-9_]*)" ~
|
||||||
|
"|[-+]?0x[0-9a-fA-F_]+" ~
|
||||||
|
"|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$"),
|
||||||
|
"-+0123456789");
|
||||||
|
regexes ~= tuple!("tag", "regexp", "chars")("tag:yaml.org,2002:merge", regex(r"^<<$"), "<");
|
||||||
|
regexes ~= tuple!("tag", "regexp", "chars")("tag:yaml.org,2002:null",
|
||||||
|
regex(r"^$|^(?:~|null|Null|NULL)$"), "~nN\0");
|
||||||
|
regexes ~= tuple!("tag", "regexp", "chars")("tag:yaml.org,2002:timestamp",
|
||||||
|
regex(r"^[0-9][0-9][0-9][0-9]-[0-9][0-9]-" ~
|
||||||
|
"[0-9][0-9]|[0-9][0-9][0-9][0-9]-[0-9]" ~
|
||||||
|
"[0-9]?-[0-9][0-9]?[Tt]|[ \t]+[0-9]" ~
|
||||||
|
"[0-9]?:[0-9][0-9]:[0-9][0-9]" ~
|
||||||
|
"(?:\\.[0-9]*)?(?:[ \t]*Z|[-+][0-9]" ~
|
||||||
|
"[0-9]?(?::[0-9][0-9])?)?$"),
|
||||||
|
"0123456789");
|
||||||
|
regexes ~= tuple!("tag", "regexp", "chars")("tag:yaml.org,2002:value", regex(r"^=$"), "=");
|
||||||
|
|
||||||
|
|
||||||
|
//The following resolver is only for documentation purposes. It cannot work
|
||||||
|
//because plain scalars cannot start with '!', '&', or '*'.
|
||||||
|
regexes ~= tuple!("tag", "regexp", "chars")("tag:yaml.org,2002:yaml", regex(r"^(?:!|&|\*)$"), "!&*");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves YAML tags (data types).
|
* Resolves YAML tags (data types).
|
||||||
*
|
*
|
||||||
* Can be used to implicitly resolve custom data types of scalar values.
|
* Can be used to implicitly resolve custom data types of scalar values.
|
||||||
*/
|
*/
|
||||||
final class Resolver
|
struct Resolver
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// Default tag to use for scalars.
|
// Default tag to use for scalars.
|
||||||
|
@ -47,24 +88,21 @@ final class Resolver
|
||||||
*/
|
*/
|
||||||
Tuple!(string, Regex!char)[][dchar] yamlImplicitResolvers_;
|
Tuple!(string, Regex!char)[][dchar] yamlImplicitResolvers_;
|
||||||
|
|
||||||
|
package:
|
||||||
|
static auto withDefaultResolvers() @safe
|
||||||
|
{
|
||||||
|
Resolver resolver;
|
||||||
|
foreach(pair; regexes)
|
||||||
|
{
|
||||||
|
resolver.addImplicitResolver(pair.tag, pair.regexp, pair.chars);
|
||||||
|
}
|
||||||
|
return resolver;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@disable bool opEquals(ref Resolver);
|
@disable bool opEquals(ref Resolver);
|
||||||
@disable int opCmp(ref Resolver);
|
@disable int opCmp(ref Resolver);
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a Resolver.
|
|
||||||
*
|
|
||||||
* If you don't want to implicitly resolve default YAML tags/data types,
|
|
||||||
* you can use defaultImplicitResolvers to disable default resolvers.
|
|
||||||
*
|
|
||||||
* Params: defaultImplicitResolvers = Use default YAML implicit resolvers?
|
|
||||||
*/
|
|
||||||
this(Flag!"useDefaultImplicitResolvers" defaultImplicitResolvers = Yes.useDefaultImplicitResolvers)
|
|
||||||
@safe
|
|
||||||
{
|
|
||||||
if(defaultImplicitResolvers){addImplicitResolvers();}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an implicit scalar resolver.
|
* Add an implicit scalar resolver.
|
||||||
*
|
*
|
||||||
|
@ -105,9 +143,7 @@ final class Resolver
|
||||||
write("example.yaml", "A");
|
write("example.yaml", "A");
|
||||||
|
|
||||||
auto loader = Loader.fromFile("example.yaml");
|
auto loader = Loader.fromFile("example.yaml");
|
||||||
auto resolver = new Resolver();
|
loader.resolver.addImplicitResolver("!tag", regex("A.*"), "A");
|
||||||
resolver.addImplicitResolver("!tag", regex("A.*"), "A");
|
|
||||||
loader.resolver = resolver;
|
|
||||||
|
|
||||||
auto node = loader.load();
|
auto node = loader.load();
|
||||||
assert(node.tag == "!tag");
|
assert(node.tag == "!tag");
|
||||||
|
@ -169,7 +205,7 @@ final class Resolver
|
||||||
}
|
}
|
||||||
@safe unittest
|
@safe unittest
|
||||||
{
|
{
|
||||||
auto resolver = new Resolver();
|
auto resolver = Resolver.withDefaultResolvers;
|
||||||
|
|
||||||
bool tagMatch(string tag, string[] values) @safe
|
bool tagMatch(string tag, string[] values) @safe
|
||||||
{
|
{
|
||||||
|
@ -215,46 +251,4 @@ final class Resolver
|
||||||
|
|
||||||
///Returns: Default mapping tag.
|
///Returns: Default mapping tag.
|
||||||
@property string defaultMappingTag() const pure @safe nothrow {return defaultMappingTag_;}
|
@property string defaultMappingTag() const pure @safe nothrow {return defaultMappingTag_;}
|
||||||
|
|
||||||
private:
|
|
||||||
// Add default implicit resolvers.
|
|
||||||
void addImplicitResolvers() @safe
|
|
||||||
{
|
|
||||||
addImplicitResolver("tag:yaml.org,2002:bool",
|
|
||||||
regex(r"^(?:yes|Yes|YES|no|No|NO|true|True|TRUE" ~
|
|
||||||
"|false|False|FALSE|on|On|ON|off|Off|OFF)$"),
|
|
||||||
"yYnNtTfFoO");
|
|
||||||
addImplicitResolver("tag:yaml.org,2002:float",
|
|
||||||
regex(r"^(?:[-+]?([0-9][0-9_]*)\\.[0-9_]*" ~
|
|
||||||
"(?:[eE][-+][0-9]+)?|[-+]?(?:[0-9][0-9_]" ~
|
|
||||||
"*)?\\.[0-9_]+(?:[eE][-+][0-9]+)?|[-+]?" ~
|
|
||||||
"[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]" ~
|
|
||||||
"*|[-+]?\\.(?:inf|Inf|INF)|\\." ~
|
|
||||||
"(?:nan|NaN|NAN))$"),
|
|
||||||
"-+0123456789.");
|
|
||||||
addImplicitResolver("tag:yaml.org,2002:int",
|
|
||||||
regex(r"^(?:[-+]?0b[0-1_]+" ~
|
|
||||||
"|[-+]?0[0-7_]+" ~
|
|
||||||
"|[-+]?(?:0|[1-9][0-9_]*)" ~
|
|
||||||
"|[-+]?0x[0-9a-fA-F_]+" ~
|
|
||||||
"|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$"),
|
|
||||||
"-+0123456789");
|
|
||||||
addImplicitResolver("tag:yaml.org,2002:merge", regex(r"^<<$"), "<");
|
|
||||||
addImplicitResolver("tag:yaml.org,2002:null",
|
|
||||||
regex(r"^$|^(?:~|null|Null|NULL)$"), "~nN\0");
|
|
||||||
addImplicitResolver("tag:yaml.org,2002:timestamp",
|
|
||||||
regex(r"^[0-9][0-9][0-9][0-9]-[0-9][0-9]-" ~
|
|
||||||
"[0-9][0-9]|[0-9][0-9][0-9][0-9]-[0-9]" ~
|
|
||||||
"[0-9]?-[0-9][0-9]?[Tt]|[ \t]+[0-9]" ~
|
|
||||||
"[0-9]?:[0-9][0-9]:[0-9][0-9]" ~
|
|
||||||
"(?:\\.[0-9]*)?(?:[ \t]*Z|[-+][0-9]" ~
|
|
||||||
"[0-9]?(?::[0-9][0-9])?)?$"),
|
|
||||||
"0123456789");
|
|
||||||
addImplicitResolver("tag:yaml.org,2002:value", regex(r"^=$"), "=");
|
|
||||||
|
|
||||||
|
|
||||||
//The following resolver is only for documentation purposes. It cannot work
|
|
||||||
//because plain scalars cannot start with '!', '&', or '*'.
|
|
||||||
addImplicitResolver("tag:yaml.org,2002:yaml", regex(r"^(?:!|&|\*)$"), "!&*");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -935,7 +935,6 @@ void testConstructor(string dataFilename, string codeDummy) @safe
|
||||||
new Exception("Unimplemented constructor test: " ~ base));
|
new Exception("Unimplemented constructor test: " ~ base));
|
||||||
|
|
||||||
auto loader = Loader.fromFile(dataFilename);
|
auto loader = Loader.fromFile(dataFilename);
|
||||||
loader.resolver = new Resolver;
|
|
||||||
|
|
||||||
Node[] exp = expected[base];
|
Node[] exp = expected[base];
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,6 @@ void testEmitterOnData(string dataFilename, string canonicalFilename) @safe
|
||||||
|
|
||||||
auto loader2 = Loader.fromString(emitStream.data);
|
auto loader2 = Loader.fromString(emitStream.data);
|
||||||
loader2.name = "TEST";
|
loader2.name = "TEST";
|
||||||
loader2.resolver = new Resolver;
|
|
||||||
auto newEvents = loader2.parse();
|
auto newEvents = loader2.parse();
|
||||||
assert(compareEvents(events, newEvents));
|
assert(compareEvents(events, newEvents));
|
||||||
}
|
}
|
||||||
|
@ -118,7 +117,6 @@ void testEmitterOnCanonical(string canonicalFilename) @safe
|
||||||
}
|
}
|
||||||
auto loader2 = Loader.fromString(emitStream.data);
|
auto loader2 = Loader.fromString(emitStream.data);
|
||||||
loader2.name = "TEST";
|
loader2.name = "TEST";
|
||||||
loader2.resolver = new Resolver;
|
|
||||||
auto newEvents = loader2.parse();
|
auto newEvents = loader2.parse();
|
||||||
assert(compareEvents(events, newEvents));
|
assert(compareEvents(events, newEvents));
|
||||||
}
|
}
|
||||||
|
@ -175,7 +173,6 @@ void testEmitterStyles(string dataFilename, string canonicalFilename) @safe
|
||||||
}
|
}
|
||||||
auto loader2 = Loader.fromString(emitStream.data);
|
auto loader2 = Loader.fromString(emitStream.data);
|
||||||
loader2.name = "TEST";
|
loader2.name = "TEST";
|
||||||
loader2.resolver = new Resolver;
|
|
||||||
auto newEvents = loader2.parse();
|
auto newEvents = loader2.parse();
|
||||||
assert(compareEvents(events, newEvents));
|
assert(compareEvents(events, newEvents));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue