aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ext_depends/D-YAML/source/dyaml/resolver.d
diff options
context:
space:
mode:
authorRalph Amissah <ralph.amissah@gmail.com>2021-02-19 17:10:51 -0500
committerRalph Amissah <ralph.amissah@gmail.com>2021-02-24 16:46:47 -0500
commit02ca32ae0a5bc290918d2b2a3288e385b9cc6b11 (patch)
tree06379785e8a0165a7deb981c2eba362894820634 /src/ext_depends/D-YAML/source/dyaml/resolver.d
parentbuild from static source-tree pre fetch depends (diff)
external & build dependences in src tree
- external & build dependences boost licensed - ext_depends (external depends) - D-YAML - tinyendian - d2sqlite3 - imageformats - build_depends - dub2nix
Diffstat (limited to 'src/ext_depends/D-YAML/source/dyaml/resolver.d')
-rw-r--r--src/ext_depends/D-YAML/source/dyaml/resolver.d261
1 files changed, 261 insertions, 0 deletions
diff --git a/src/ext_depends/D-YAML/source/dyaml/resolver.d b/src/ext_depends/D-YAML/source/dyaml/resolver.d
new file mode 100644
index 0000000..ceed1e5
--- /dev/null
+++ b/src/ext_depends/D-YAML/source/dyaml/resolver.d
@@ -0,0 +1,261 @@
+
+// Copyright Ferdinand Majerech 2011.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+/**
+ * Implements a class that resolves YAML tags. This can be used to implicitly
+ * resolve tags for custom data types, removing the need to explicitly
+ * specify tags in YAML. A tutorial can be found
+ * $(LINK2 ../tutorials/custom_types.html, here).
+ *
+ * Code based on $(LINK2 http://www.pyyaml.org, PyYAML).
+ */
+module dyaml.resolver;
+
+
+import std.conv;
+import std.regex;
+import std.typecons;
+import std.utf;
+
+import dyaml.node;
+import dyaml.exception;
+
+
+/// Type of `regexes`
+private alias RegexType = Tuple!(string, "tag", const Regex!char, "regexp", string, "chars");
+
+private immutable RegexType[] regexes;
+
+shared static this() @safe
+{
+ RegexType[] tmp;
+ tmp ~= RegexType("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");
+ tmp ~= RegexType("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.");
+ tmp ~= RegexType("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");
+ tmp ~= RegexType("tag:yaml.org,2002:merge", regex(r"^<<$"), "<");
+ tmp ~= RegexType("tag:yaml.org,2002:null",
+ regex(r"^$|^(?:~|null|Null|NULL)$"), "~nN\0");
+ tmp ~= RegexType("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");
+ tmp ~= RegexType("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 '*'.
+ tmp ~= RegexType("tag:yaml.org,2002:yaml", regex(r"^(?:!|&|\*)$"), "!&*");
+
+ regexes = () @trusted { return cast(immutable)tmp; }();
+}
+
+/**
+ * Resolves YAML tags (data types).
+ *
+ * Can be used to implicitly resolve custom data types of scalar values.
+ */
+struct Resolver
+{
+ private:
+ // Default tag to use for scalars.
+ string defaultScalarTag_ = "tag:yaml.org,2002:str";
+ // Default tag to use for sequences.
+ string defaultSequenceTag_ = "tag:yaml.org,2002:seq";
+ // Default tag to use for mappings.
+ string defaultMappingTag_ = "tag:yaml.org,2002:map";
+
+ /*
+ * 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, const 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:
+ @disable bool opEquals(ref Resolver);
+ @disable int opCmp(ref Resolver);
+
+ /**
+ * Add an implicit scalar resolver.
+ *
+ * If a scalar matches regexp and starts with any character in first,
+ * its _tag is set to tag. If it matches more than one resolver _regexp
+ * resolvers added _first override ones added later. Default resolvers
+ * override any user specified resolvers, but they can be disabled in
+ * Resolver constructor.
+ *
+ * If a scalar is not resolved to anything, it is assigned the default
+ * YAML _tag for strings.
+ *
+ * Params: tag = Tag to resolve to.
+ * regexp = Regular expression the scalar must match to have this _tag.
+ * first = String of possible starting characters of the scalar.
+ *
+ */
+ void addImplicitResolver(string tag, const Regex!char regexp, string first)
+ pure @safe
+ {
+ foreach(const dchar c; first)
+ {
+ if((c in yamlImplicitResolvers_) is null)
+ {
+ yamlImplicitResolvers_[c] = [];
+ }
+ yamlImplicitResolvers_[c] ~= tuple(tag, regexp);
+ }
+ }
+ /// Resolve scalars starting with 'A' to !_tag
+ @safe unittest
+ {
+ import std.file : write;
+ import std.regex : regex;
+ import dyaml.loader : Loader;
+ import dyaml.resolver : Resolver;
+
+ write("example.yaml", "A");
+
+ auto loader = Loader.fromFile("example.yaml");
+ loader.resolver.addImplicitResolver("!tag", regex("A.*"), "A");
+
+ auto node = loader.load();
+ assert(node.tag == "!tag");
+ }
+
+ package:
+ /**
+ * Resolve tag of a node.
+ *
+ * Params: kind = Type of the node.
+ * tag = Explicit tag of the node, if any.
+ * value = Value of the node, if any.
+ * implicit = Should the node be implicitly resolved?
+ *
+ * If the tag is already specified and not non-specific, that tag will
+ * be returned.
+ *
+ * Returns: Resolved tag.
+ */
+ string resolve(const NodeID kind, const string tag, const string value,
+ const bool implicit) @safe
+ {
+ import std.array : empty, front;
+ if((tag !is null) && (tag != "!"))
+ {
+ return tag;
+ }
+
+ final switch (kind)
+ {
+ case NodeID.scalar:
+ if(!implicit)
+ {
+ return defaultScalarTag_;
+ }
+
+ //Get the first char of the value.
+ const dchar first = value.empty ? '\0' : value.front;
+
+ auto resolvers = (first in yamlImplicitResolvers_) is null ?
+ [] : yamlImplicitResolvers_[first];
+
+ //If regexp matches, return tag.
+ foreach(resolver; resolvers)
+ {
+ if(!(match(value, resolver[1]).empty))
+ {
+ return resolver[0];
+ }
+ }
+ return defaultScalarTag_;
+ case NodeID.sequence:
+ return defaultSequenceTag_;
+ case NodeID.mapping:
+ return defaultMappingTag_;
+ case NodeID.invalid:
+ assert(false, "Cannot resolve an invalid node");
+ }
+ }
+ @safe unittest
+ {
+ auto resolver = Resolver.withDefaultResolvers;
+
+ bool tagMatch(string tag, string[] values) @safe
+ {
+ const string expected = tag;
+ foreach(value; values)
+ {
+ const string resolved = resolver.resolve(NodeID.scalar, null, value, true);
+ if(expected != resolved)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ assert(tagMatch("tag:yaml.org,2002:bool",
+ ["yes", "NO", "True", "on"]));
+ assert(tagMatch("tag:yaml.org,2002:float",
+ ["6.8523015e+5", "685.230_15e+03", "685_230.15",
+ "190:20:30.15", "-.inf", ".NaN"]));
+ assert(tagMatch("tag:yaml.org,2002:int",
+ ["685230", "+685_230", "02472256", "0x_0A_74_AE",
+ "0b1010_0111_0100_1010_1110", "190:20:30"]));
+ assert(tagMatch("tag:yaml.org,2002:merge", ["<<"]));
+ assert(tagMatch("tag:yaml.org,2002:null", ["~", "null", ""]));
+ assert(tagMatch("tag:yaml.org,2002:str",
+ ["abcd", "9a8b", "9.1adsf"]));
+ assert(tagMatch("tag:yaml.org,2002:timestamp",
+ ["2001-12-15T02:59:43.1Z",
+ "2001-12-14t21:59:43.10-05:00",
+ "2001-12-14 21:59:43.10 -5",
+ "2001-12-15 2:59:43.10",
+ "2002-12-14"]));
+ assert(tagMatch("tag:yaml.org,2002:value", ["="]));
+ assert(tagMatch("tag:yaml.org,2002:yaml", ["!", "&", "*"]));
+ }
+
+ ///Returns: Default scalar tag.
+ @property string defaultScalarTag() const pure @safe nothrow {return defaultScalarTag_;}
+
+ ///Returns: Default sequence tag.
+ @property string defaultSequenceTag() const pure @safe nothrow {return defaultSequenceTag_;}
+
+ ///Returns: Default mapping tag.
+ @property string defaultMappingTag() const pure @safe nothrow {return defaultMappingTag_;}
+}