diff options
author | Ralph Amissah <ralph.amissah@gmail.com> | 2021-02-19 17:10:51 -0500 |
---|---|---|
committer | Ralph Amissah <ralph.amissah@gmail.com> | 2021-02-24 16:46:47 -0500 |
commit | 02ca32ae0a5bc290918d2b2a3288e385b9cc6b11 (patch) | |
tree | 06379785e8a0165a7deb981c2eba362894820634 /src/ext_depends/D-YAML | |
parent | build 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')
574 files changed, 19508 insertions, 0 deletions
diff --git a/src/ext_depends/D-YAML/.codecov.yml b/src/ext_depends/D-YAML/.codecov.yml new file mode 100644 index 0000000..7e05d9f --- /dev/null +++ b/src/ext_depends/D-YAML/.codecov.yml @@ -0,0 +1,13 @@ +# Documentation: https://github.com/codecov/support/wiki/codecov.yml +codecov: +coverage: + precision: 3 + round: down + + status: + # Learn more at https://codecov.io/docs#yaml_default_commit_status + project: true + patch: true + changes: false + +comment: false diff --git a/src/ext_depends/D-YAML/.editorconfig b/src/ext_depends/D-YAML/.editorconfig new file mode 100644 index 0000000..aa1b122 --- /dev/null +++ b/src/ext_depends/D-YAML/.editorconfig @@ -0,0 +1,14 @@ +# EditorConfig file: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +end_of_line = lf +insert_final_newline = true + +[*.d] +charset = utf-8 +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true diff --git a/src/ext_depends/D-YAML/.gitignore b/src/ext_depends/D-YAML/.gitignore new file mode 100644 index 0000000..1a1aec4 --- /dev/null +++ b/src/ext_depends/D-YAML/.gitignore @@ -0,0 +1,66 @@ +/__test__library__ +/examples/resolver/resolver +/examples/representer/representer +/examples/getting_started/getting-started +/examples/constructor/constructor +/libdyaml +/examples/yaml_gen/yaml_gen +/unittest.obj +/examples/yaml_stats/yaml_stats +/examples/yaml_bench/yaml_bench +/examples/representer/output.yaml +/examples/getting_started/output.yaml +/examples/getting_started/main.obj +/cdc.obj +/unittest + +# Backups # +########### +*~ +*.sw* + +# dub # +####### +*.dub* +dub.selections.json + +# Compiled source # +################### +unittest +cdc +main +*.a +*.lib +*.o +*.obj +*.exe +docs.json + +# Packages # +############ +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.tar +*.tar.xz +*.tar.gz +*.zip + +# OS generated files # +###################### +.DS_Store? +ehthumbs.db +Icon? +Thumbs.db +.directory + +# Profiling outputs # +##################### +perf.data +perf.data.old +callgrind.out.* + +# Test outputs # +example.yaml + +# Unittest Coverage output # +*.lst diff --git a/src/ext_depends/D-YAML/.travis.yml b/src/ext_depends/D-YAML/.travis.yml new file mode 100644 index 0000000..7e284b6 --- /dev/null +++ b/src/ext_depends/D-YAML/.travis.yml @@ -0,0 +1,41 @@ +dist: xenial +sudo: false + +language: d +os: + - linux +d: + - dmd + - ldc + +branches: + only: + - master + +before_install: + - sudo apt-get install python3-pip python3-setuptools + - pip3 install 'meson==0.48.2' + +install: + - mkdir .ntmp && curl -L https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip -o .ntmp/ninja-linux.zip + - unzip .ntmp/ninja-linux.zip -d .ntmp + +before_script: + - export PATH=$PATH:$PWD/.ntmp + +script: + - meson build && ninja -j8 -C build + - ninja -j8 -C build test -v + - dub build + - "dub build dyaml:benchmark" + - "dub build dyaml:constructor" + - "dub build dyaml:getting-started" + - "dub build dyaml:representer" + - "dub build dyaml:resolver" + - "dub build dyaml:testsuite" + - "dub build dyaml:tojson" + - "dub build dyaml:yaml_gen" + - "dub build dyaml:yaml_stats" + - dub test --build=unittest-cov +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/src/ext_depends/D-YAML/LICENSE_1_0.txt b/src/ext_depends/D-YAML/LICENSE_1_0.txt new file mode 100644 index 0000000..36b7cd9 --- /dev/null +++ b/src/ext_depends/D-YAML/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/ext_depends/D-YAML/README.md b/src/ext_depends/D-YAML/README.md new file mode 100644 index 0000000..4781bdd --- /dev/null +++ b/src/ext_depends/D-YAML/README.md @@ -0,0 +1,97 @@ +# D:YAML + +[![travis-ci](https://travis-ci.org/dlang-community/D-YAML.svg?branch=master)](https://travis-ci.org/dlang-community/D-YAML) +[![codecov](https://codecov.io/gh/dlang-community/D-YAML/branch/master/graph/badge.svg)](https://codecov.io/gh/dlang-community/D-YAML) +[![code.dlang.org](https://img.shields.io/dub/v/dyaml.svg)](http://code.dlang.org/packages/dyaml) + +## Introduction + +D:YAML is an open source YAML parser and emitter library for the D programming language. +It is [almost](https://dlang-community.github.io/D-YAML/articles/spec_differences.html) compliant to the YAML 1.1 specification. +D:YAML is based on [PyYAML](http://www.pyyaml.org) created by Kirill Simonov. + +D:YAML is designed to be easy to use while supporting the full feature set of YAML. +To start using it in your project, see the [Getting Started](https://dlang-community.github.io/D-YAML/tutorials/getting_started.html) tutorial. + +## Features + + - Easy to use, high level API and detailed debugging messages. + - Detailed API documentation and tutorials. + - Code examples. + - Supports all YAML 1.1 constructs. All examples from the YAML 1.1 + specification are parsed correctly. + - Reads from and writes from/to YAML files or in-memory buffers. + - UTF-8, UTF-16 and UTF-32 encodings are supported, both big and + little endian (plain ASCII also works as it is a subset of UTF-8). + - Support for both block (Python-like, based on indentation) and flow + (JSON-like, based on bracing) constructs. + - Support for YAML anchors and aliases. + - Support for default values in mappings. + - Support for custom tags (data types), and implicit tag resolution + for custom scalar tags. + - All tags (data types) described at <http://yaml.org/type/> are + supported, with the exception of `tag:yaml.org,2002:yaml`, which is + used to represent YAML code in YAML. + - Remembers YAML style information between loading and dumping if + possible. + - Reuses input memory and uses slices to minimize memory allocations. + - There is no support for recursive data structures. There are no + plans to implement this at the moment. + +## Directory structure + +| Directory | Contents | +|---------------|--------------------------------| +| `./` | This README, utility scripts. | +| `./docs` | Documentation. | +| `./source` | Source code. | +| `./examples/` | Example projects using D:YAML. | +| `./test` | Unittest data. | + +## Installing and tutorial + +See the [Getting Started](https://dlang-community.github.io/D-YAML/tutorials/getting_started.html). +Tutorial and other tutorials that can be found at the [GitHub pages](https://dlang-community.github.io/D-YAML/) or in the `docs` directory of the repository. + +API documentation is available [here](https://dyaml.dpldocs.info/dyaml.html). + +## License + +D:YAML is released under the terms of the [Boost Software +License 1.0](http://www.boost.org/LICENSE_1_0.txt). This license allows +you to use the source code in your own projects, open source or +proprietary, and to modify it to suit your needs. However, in source +distributions, you have to preserve the license headers in the source +code and the accompanying license file. + +Full text of the license can be found in file `LICENSE_1_0.txt` and is +also displayed here: + + Boost Software License - Version 1.0 - August 17th, 2003 + + Permission is hereby granted, free of charge, to any person or organization + obtaining a copy of the software and accompanying documentation covered by + this license (the "Software") to use, reproduce, display, distribute, + execute, and transmit the Software, and to prepare derivative works of the + Software, and to permit third-parties to whom the Software is furnished to + do so, all subject to the following: + + The copyright notices in the Software and this entire statement, including + the above license grant, this restriction and the following disclaimer, + must be included in all copies of the Software, in whole or in part, and + all derivative works of the Software, unless such copies or derivative + works are solely in the form of machine-executable object code generated by + a source language processor. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + +## Credits + +D:YAML was created by Ferdinand Majerech aka Kiith-Sa and is handled by the [dlang-community](https://github.com/dlang-community) organization since 2017. +Parts of code based on [PyYAML](http://www.pyyaml.org) created by Kirill Simonov. diff --git a/src/ext_depends/D-YAML/appveyor.yml b/src/ext_depends/D-YAML/appveyor.yml new file mode 100644 index 0000000..1efa6be --- /dev/null +++ b/src/ext_depends/D-YAML/appveyor.yml @@ -0,0 +1,122 @@ +platform: x64 +environment: + matrix: + #- DC: dmd + # DVersion: nightly + # arch: x64 + #- DC: dmd + # DVersion: nightly + # arch: x86 + #- DC: dmd + # DVersion: beta + # arch: x64 + #- DC: dmd + # DVersion: beta + # arch: x86 + - DC: dmd + DVersion: stable + arch: x64 + - DC: dmd + DVersion: stable + arch: x86 + #- DC: ldc + # DVersion: beta + # arch: x86 + #- DC: ldc + # DVersion: beta + # arch: x64 + - DC: ldc + DVersion: stable + arch: x86 + - DC: ldc + DVersion: stable + arch: x64 + +skip_tags: false +branches: + only: + - master + +install: + - ps: function ResolveLatestDMD + { + $version = $env:DVersion; + if($version -eq "stable") { + $latest = (Invoke-WebRequest "http://downloads.dlang.org/releases/LATEST").toString(); + $url = "http://downloads.dlang.org/releases/2.x/$($latest)/dmd.$($latest).windows.7z"; + }elseif($version -eq "beta") { + $latest = (Invoke-WebRequest "http://downloads.dlang.org/pre-releases/LATEST").toString(); + $latestVersion = $latest.split("-")[0].split("~")[0]; + $url = "http://downloads.dlang.org/pre-releases/2.x/$($latestVersion)/dmd.$($latest).windows.7z"; + }elseif($version -eq "nightly") { + $url = "http://nightlies.dlang.org/dmd-master-2017-05-20/dmd.master.windows.7z" + }else { + $url = "http://downloads.dlang.org/releases/2.x/$($version)/dmd.$($version).windows.7z"; + } + $env:PATH += ";C:\dmd2\windows\bin;"; + return $url; + } + - ps: function ResolveLatestLDC + { + $version = $env:DVersion; + $arch = $env:arch; + if($version -eq "stable") { + $latest = (Invoke-WebRequest "https://ldc-developers.github.io/LATEST").toString().replace("`n","").replace("`r",""); + $url = "https://github.com/ldc-developers/ldc/releases/download/v$($latest)/ldc2-$($latest)-windows-$($arch).7z"; + }elseif($version -eq "beta") { + $latest = (Invoke-WebRequest "https://ldc-developers.github.io/LATEST_BETA").toString().replace("`n","").replace("`r",""); + $url = "https://github.com/ldc-developers/ldc/releases/download/v$($latest)/ldc2-$($latest)-windows-$($arch).7z"; + } else { + $latest = $version; + $url = "https://github.com/ldc-developers/ldc/releases/download/v$($version)/ldc2-$($version)-windows-$($arch).7z"; + } + $env:PATH += ";C:\ldc2-$($latest)-windows-$($arch)\bin"; + $env:DC = "ldc2"; + return $url; + } + - ps: function SetUpDCompiler + { + $env:toolchain = "msvc"; + if($env:DC -eq "dmd"){ + echo "downloading ..."; + $url = ResolveLatestDMD; + echo $url; + Invoke-WebRequest $url -OutFile "c:\dmd.7z"; + echo "finished."; + pushd c:\\; + 7z x dmd.7z > $null; + popd; + } + elseif($env:DC -eq "ldc"){ + echo "downloading ..."; + $url = ResolveLatestLDC; + echo $url; + Invoke-WebRequest $url -OutFile "c:\ldc.zip"; + echo "finished."; + pushd c:\\; + 7z x ldc.zip > $null; + popd; + } + } + - ps: SetUpDCompiler + +build_script: + - ps: if($env:arch -eq "x86"){ + $env:compilersetupargs = "x86"; + $env:Darch = "x86"; + $env:DConf = "m32"; + }elseif($env:arch -eq "x64"){ + $env:compilersetupargs = "amd64"; + $env:Darch = "x86_64"; + $env:DConf = "m64"; + } + - ps: $env:compilersetup = "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall"; + - '"%compilersetup%" %compilersetupargs%' + +test_script: + - echo %PLATFORM% + - echo %Darch% + - echo %DC% + - echo %PATH% + - '%DC% --version' + - dub test --arch=%Darch% --compiler=%DC% diff --git a/src/ext_depends/D-YAML/contrib/tinyendian.wrap b/src/ext_depends/D-YAML/contrib/tinyendian.wrap new file mode 100644 index 0000000..550553b --- /dev/null +++ b/src/ext_depends/D-YAML/contrib/tinyendian.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory = tinyendian + +url = https://github.com/dlang-community/tinyendian.git +revision = head diff --git a/src/ext_depends/D-YAML/docs/articles/spec_differences.md b/src/ext_depends/D-YAML/docs/articles/spec_differences.md new file mode 100644 index 0000000..93cf038 --- /dev/null +++ b/src/ext_depends/D-YAML/docs/articles/spec_differences.md @@ -0,0 +1,64 @@ +# Differences between D:YAML and the YAML specification + +There are some differences between D:YAML and the YAML 1.1 +specification. Some are caused by difficulty of implementation of some +features, such as multiple Unicode encodings within single stream, and +some by unnecessary restrictions or ambiguities in the specification. + +Still, D:YAML tries to be as close to the specification as possible. It +should never load documents with different meaning than according to the +specification, and documents that fail to load should be very rare (for +instance, very few files use multiple Unicode encodings). + +## List of known differences: + +Differences that can cause valid YAML documents not to load: + + - No support for byte order marks and multiple Unicode encodings in a + stream. + + - Plain scalars in flow context cannot contain `,`, `:` and `?`. This + might change with `:` in the future. See + <http://pyyaml.org/wiki/YAMLColonInFlowContext> for details. + + - The specification does not restrict characters for anchors and + aliases. This may lead to problems, for instance, the document: + + [ *alias, value ] + + can be interpteted in two ways, as: + + [ "value" ] + + and: + + [ *alias , "value" ] + + Therefore we restrict aliases and anchors to ASCII alphanumeric + characters. + + - The specification is confusing about tabs in plain scalars. We don't + use tabs in plain scalars at all. + + - There is no support for recursive data structures in DYAML. + +Other differences: + + - Indentation is ignored in the flow context, which is less + restrictive than the specification. This allows code such as: + + key: { + } + + - Indentation rules for quoted scalars are loosed: They don't need to + adhere indentation as `"` and `'` clearly mark the beginning and the + end of them. + + - We allow `_` in tag handles. + + - Right now, two mappings with the same contents but different + orderings are considered unequal, even if they are unordered + mappings. This is because all mappings are ordered in the D:YAML + implementation. This should change in future, once D associative + arrays work with variant types or a map class or struct appears in + Phobos. diff --git a/src/ext_depends/D-YAML/docs/index.md b/src/ext_depends/D-YAML/docs/index.md new file mode 100644 index 0000000..d0017ea --- /dev/null +++ b/src/ext_depends/D-YAML/docs/index.md @@ -0,0 +1,11 @@ +# Welcome to D:YAML documentation! + +API Documentation [online](https://dyaml.dpldocs.info/dyaml.html) + +Tutorials: + - [Getting Started](tutorials/getting_started.md) + - [Custom Types](tutorials/custom_types.md) + - [YAML Syntax](tutorials/yaml_syntax.md) + +Articles: + - [Spec Differences](articles/spec_differences.md) diff --git a/src/ext_depends/D-YAML/docs/logo128.png b/src/ext_depends/D-YAML/docs/logo128.png Binary files differnew file mode 100644 index 0000000..f00ae05 --- /dev/null +++ b/src/ext_depends/D-YAML/docs/logo128.png diff --git a/src/ext_depends/D-YAML/docs/logo210.png b/src/ext_depends/D-YAML/docs/logo210.png Binary files differnew file mode 100644 index 0000000..66bef66 --- /dev/null +++ b/src/ext_depends/D-YAML/docs/logo210.png diff --git a/src/ext_depends/D-YAML/docs/tutorials/custom_types.md b/src/ext_depends/D-YAML/docs/tutorials/custom_types.md new file mode 100644 index 0000000..7e4e10b --- /dev/null +++ b/src/ext_depends/D-YAML/docs/tutorials/custom_types.md @@ -0,0 +1,258 @@ +# Custom YAML data types + +Sometimes you need to serialize complex data types such as classes. To +do this you could use plain nodes such as mappings with classes' fields. +YAML also supports custom types with identifiers called *tags*. That is +the topic of this tutorial. + +Each YAML node has a tag specifying its type. For instance: strings use +the tag `tag:yaml.org,2002:str`. Tags of most default types are +*implicitly resolved* during parsing - you don't need to specify tag for +each float, integer, etc. D:YAML can also implicitly resolve custom +tags, as we will show later. + +## Constructor + +D:YAML supports conversion to user-defined types. Adding a constructor to read +the data from the node is all that is needed. + +We will implement support for an RGB color type. It is implemented as +the following struct: + +```D +struct Color +{ + ubyte red; + ubyte green; + ubyte blue; +} +``` + +First, we need our type to have an appropriate constructor. The constructor +will take a const *Node* to construct from. The node is guaranteed to +contain either a *string*, an array of *Node* or of *Node.Pair*, +depending on whether we're constructing our value from a scalar, +sequence, or mapping, respectively. + +In this tutorial, we have a constructor to construct a color from a scalar, +using CSS-like format, RRGGBB, or from a mapping, where we use the +following format: {r:RRR, g:GGG, b:BBB} . Code of these functions: + +```D + +this(const Node node, string tag) @safe +{ + if (tag == "!color-mapping") + { + //Will throw if a value is missing, is not an integer, or is out of range. + red = node["r"].as!ubyte; + green = node["g"].as!ubyte; + blue = node["b"].as!ubyte; + } + else + { + string value = node.as!string; + + if(value.length != 6) + { + throw new Exception("Invalid color: " ~ value); + } + //We don't need to check for uppercase chars this way. + value = value.toLower(); + + //Get value of a hex digit. + uint hex(char c) + { + import std.ascii; + if(!std.ascii.isHexDigit(c)) + { + throw new Exception("Invalid color: " ~ value); + } + + if(std.ascii.isDigit(c)) + { + return c - '0'; + } + return c - 'a' + 10; + } + + red = cast(ubyte)(16 * hex(value[0]) + hex(value[1])); + green = cast(ubyte)(16 * hex(value[2]) + hex(value[3])); + blue = cast(ubyte)(16 * hex(value[4]) + hex(value[5])); + } +} +``` + +Next, we need some YAML data using our new tag. Create a file called +`input.yaml` with the following contents: + +```YAML +scalar-red: !color FF0000 +scalar-orange: !color FFFF00 +mapping-red: !color-mapping {r: 255, g: 0, b: 0} +mapping-orange: + !color-mapping + r: 255 + g: 255 + b: 0 +``` + +You can see that we're using tag `!color` for scalar colors, and +`!color-mapping` for colors expressed as mappings. + +Finally, the code to put it all together: + +```D +void main() +{ + auto red = Color(255, 0, 0); + auto orange = Color(255, 255, 0); + + try + { + auto root = Loader.fromFile("input.yaml").load(); + + if(root["scalar-red"].as!Color == red && + root["mapping-red"].as!Color == red && + root["scalar-orange"].as!Color == orange && + root["mapping-orange"].as!Color == orange) + { + writeln("SUCCESS"); + return; + } + } + catch(YAMLException e) + { + writeln(e.msg); + } + + writeln("FAILURE"); +} +``` + +First we load the YAML document, and then have the resulting *Node*s converted +to Colors via their constructor. + +You can find the source code for what we've done so far in the +`examples/constructor` directory in the D:YAML package. + +## Resolver + +Specifying tag for every color can be tedious. D:YAML can implicitly +resolve scalar tags using regular expressions. This is how default types +are resolved. We will use the [Resolver](../api/dyaml.resolver.html) +class to add implicit tag resolution for the Color data type (in its +scalar form). + +We use the *addImplicitResolver()* method of *Resolver*, passing the +tag, regular expression the scalar must match to resolve to this tag, +and a string of possible starting characters of the scalar. Then we pass +the *Resolver* to *Loader*. + +Note that resolvers added first override ones added later. If no +resolver matches a scalar, YAML string tag is used. Therefore our custom +values must not be resolvable as any non-string YAML data type. + +Add this to your code to add implicit resolution of `!color`. + +```D +import std.regex; +auto resolver = new Resolver; +resolver.addImplicitResolver("!color", regex("[0-9a-fA-F]{6}"), + "0123456789abcdefABCDEF"); + +auto loader = Loader.fromFile("input.yaml"); + +loader.resolver = resolver; +``` + +Now, change contents of `input.yaml` to this: + +```YAML +scalar-red: FF0000 +scalar-orange: FFFF00 +mapping-red: !color-mapping {r: 255, g: 0, b: 0} +mapping-orange: + !color-mapping + r: 255 + g: 255 + b: 0 +``` + +We no longer need to specify the tag for scalar color values. Compile +and test the example. If everything went as expected, it should report +success. + +You can find the complete code in the `examples/resolver` directory in +the D:YAML package. + +## Representer + +Now that you can load custom data types, it might be good to know how to +dump them. + +The *Node* struct simply attempts to cast all unrecognized types to *Node*. +This gives each type a consistent and simple way of being represented in a +document. All we need to do is specify a `Node opCast(T: Node)()` method for +any types we wish to support. It is also possible to specify specific styles +for each representation. + +Each type may only have one opCast!Node. Default YAML types are already +supported. + +With the following code, we will add support for dumping the our Color +type. + +```D +Node opCast(T: Node)() const +{ + static immutable hex = "0123456789ABCDEF"; + + //Using the color format from the Constructor example. + string scalar; + foreach(channel; [red, green, blue]) + { + scalar ~= hex[channel / 16]; + scalar ~= hex[channel % 16]; + } + + //Representing as a scalar, with custom tag to specify this data type. + return Node(scalar, "!color"); +} +``` + +First we convert the colour data to a string with the CSS-like format we've +used before. Then, we create a scalar *Node* with our desired tag. + +Since a type can only have one opCast!Node method, we don't dump +*Color* both in the scalar and mapping formats we've used before. +However, you can decide to dump the node with different formats/tags in +the method itself. E.g. you could dump the Color as a +mapping based on some arbitrary condition, such as the color being +white. + +```D +void main() +{ + try + { + auto dumper = dumper(File("output.yaml", "w").lockingTextWriter); + + auto document = Node([Color(255, 0, 0), + Color(0, 255, 0), + Color(0, 0, 255)]); + + dumper.dump(document); + } + catch(YAMLException e) + { + writeln(e.msg); + } +} +``` + +We construct a *Dumper* to file `output.yaml`. Then, we create a simple node +containing a sequence of colors and finally, we dump it. + +Source code for this section can be found in the `examples/representer` +directory of the D:YAML package. diff --git a/src/ext_depends/D-YAML/docs/tutorials/getting_started.md b/src/ext_depends/D-YAML/docs/tutorials/getting_started.md new file mode 100644 index 0000000..58cf191 --- /dev/null +++ b/src/ext_depends/D-YAML/docs/tutorials/getting_started.md @@ -0,0 +1,140 @@ +# Getting started + +Welcome to D:YAML\! D:YAML is a +[YAML](http://en.wikipedia.org/wiki/YAML) parser library for the [D +programming language](http://dlang.org). This tutorial will explain how +to set D:YAML up and use it in your projects. + +This is meant to be the **simplest possible** introduction to D:YAML. +Some of this information might already be known to you. Only basic usage +is covered. + +## Setting up + +### Install the DMD compiler + +Digital Mars D compiler, or DMD, is the most commonly used D compiler. +You can find its newest version [here](http://dlang.org/download.html). +Download the version of DMD for your operating system and install it. + +Note: Other D compilers exist, such as [GDC](http://gdcproject.org/) and +[LDC](https://github.com/ldc-developers/ldc). + +## Your first D:YAML project + +First, create a directory for your project and navigate to that directory +using your preferred command line. Then simply execute these two commands: + + dub init + dub add dyaml + +In that directory, create a new file named `input.yaml` and paste this data +into the file: + +```YAML +Hello World : [Hello, World] +Answer: 42 +``` + +This will serve as input for our example. + +Now we need to parse it. Open the file named `source/app.d` and paste the +following code into the file: + +```D +import std.stdio; +import dyaml; + +void main() +{ + //Read the input. + Node root = Loader.fromFile("input.yaml").load(); + + //Display the data read. + foreach(string word; root["Hello World"]) + { + writeln(word); + } + writeln("The answer is ", root["Answer"].as!int); + + //Dump the loaded document to output.yaml. + dumper(File("output.yaml", "w").lockingTextWriter).dump(root); +} +``` + +### Explanation of the code + +First, we import the *dyaml* module. This is the only D:YAML module +you need to import - it automatically imports all needed modules. + +Next we load the file using the *Loader.fromFile().load()* method. *Loader* is a +struct used for parsing YAML documents. The *fromFile()* method loads the +document from a file. The *load()* method loads the +file as **one** YAML document, or throws *YAMLException*, D:YAML +exception type, if the file could not be parsed or contains more than +one document. Note that we don't do any error checking here in order to +keep the example as simple as possible. + +*Node* represents a node in a YAML document. It can be a sequence +(array), mapping (associative array) or a scalar (value). Here the root +node is a mapping, and we use the index operator to get subnodes with +keys "Hello World" and "Answer". We iterate over the former, as it is a +sequence, and use the *Node.as()* method on the latter to read its value +as an integer. + +You can iterate over a mapping or sequence as if it was an associative +or normal array, respectively. If you try to iterate over a scalar, it +will throw a *YAMLException*. + +You can iterate using *Node* as the iterated type, or specify the type +iterated nodes are expected to have. D:YAML will automatically convert +to that type if possible. Here we specify the *string* type, so we +iterate over the "Hello World" sequence as an array of strings. If it is +not possible to convert to iterated type, a *YAMLException* is thrown. +For instance, if we specified *int* here, we would get an error, as +"Hello" cannot be converted to an integer. + +The *Node.as()* method is used to read value of a scalar node as +specified type. If the scalar does not have the specified type, D:YAML +will try to convert it, throwing *YAMLException* if not possible. + +Finally we dump the document we just read to `output.yaml` with the +*Dumper.dump()* method. *Dumper* is a struct used to dump YAML +documents. *dumper()* accepts a range to write the document to. +The *dump()* method writes one or more documents to the range, +throwing *YAMLException* if it could not be written to. + +D:YAML tries to preserve style information in documents so e.g. `[Hello, +World]` is not turned into: + +```YAML +- Hello +- World +``` + +However, comments are not preserved and neither are any extra formatting +whitespace that doesn't affect the meaning of YAML contents. + +### Compiling + +Run the following command in your project's directory: + + dub build + +DUB will automatically download D:YAML and compile it, and then it +will compile our program. This will generate an executable called +`getting-started` or `getting-started.exe` in your directory. When you +run it, it should produce the following output: + + Hello + World + The answer is 42 + +You may also run ```dub run``` to combine the compile+run steps. + +### Conclusion + +You should now have a basic idea about how to use D:YAML. To learn more, +look at the [API documentation](https://dyaml.dpldocs.info/dyaml.html) and other tutorials. +You can find code for this example in the `example/getting_started` +directory in the package. diff --git a/src/ext_depends/D-YAML/docs/tutorials/yaml_syntax.md b/src/ext_depends/D-YAML/docs/tutorials/yaml_syntax.md new file mode 100644 index 0000000..2df7f8b --- /dev/null +++ b/src/ext_depends/D-YAML/docs/tutorials/yaml_syntax.md @@ -0,0 +1,241 @@ +# YAML syntax + +This is an introduction to the most common YAML constructs. For more detailed +information, see [PyYAML documentation](http://pyyaml.org/wiki/PyYAMLDocumentation), +which this article is based on, +[Chapter 2 of the YAML specification](http://yaml.org/spec/1.1/#id857168) +or the [Wikipedia page](http://en.wikipedia.org/wiki/YAML). + +YAML is a data serialization format designed for human readability. YAML is a +recursive acronym for "YAML Ain't Markup Language". + +YAML is similar to JSON, and in fact, JSON is a subset of YAML 1.2; but YAML has +some more advanced features and is easier to read. However, it is also more +difficult to parse (and probably somewhat slower). Data is stored in mappings +(associative arrays), sequences (lists) and scalars (single values). Data +structure hierarchy depends either on indentation (block context, similar to +Python code), or nesting of brackets and braces (flow context, similar to JSON). +YAML comments begin with `#` and continue until the end of line. + + +## Documents + +A YAML stream consists of one or more documents starting with `---` and +optionally ending with `...` . `---` can be left out for the first document. + +Single document with no explicit start or end: + +``` + - Red + - Green + - Blue +``` +Same document with explicit start and end: +``` + --- + - Red + - Green + - Blue + ... +``` +A stream containing multiple documents: +``` + --- + - Red + - Green + - Blue + --- + - Linux + - BSD + --- + answer : 42 +``` + +## Sequences + +Sequences are arrays of nodes of any type, similar e.g. to Python lists. +In block context, each item begins with hyphen+space "- ". In flow context, +sequences have syntax similar to D arrays. + +``` + #Block context + - Red + - Green + - Blue +``` +``` + #Flow context + [Red, Green, Blue] +``` +``` + #Nested + - + - Red + - Green + - Blue + - + - Linux + - BSD +``` +``` + #Nested flow + [[Red, Green, Blue], [Linux, BSD]] +``` +``` + #Nested in a mapping + Colors: + - Red + - Green + - Blue + Operating systems: + - Linux + - BSD +``` + +## Mappings + +Mappings are associative arrays where each key and value can be of any type, +similar e.g. to Python dictionaries. In block context, keys and values are +separated by colon+space ": ". In flow context, mappings have syntax similar +to D associative arrays, but with braces instead of brackets: + +``` + #Block context + CPU: Athlon + GPU: Radeon + OS: Linux + +``` +``` + #Flow context + {CPU: Athlon, GPU: Radeon, OS: Linux} + +``` +``` + #Nested + PC: + CPU: Athlon + GPU: Radeon + OS: Debian + Phone: + CPU: Cortex + GPU: PowerVR + OS: Android + +``` +``` + #Nested flow + {PC: {CPU: Athlon, GPU: Radeon, OS: Debian}, + Phone: {CPU: Cortex, GPU: PowerVR, OS: Android}} +``` +``` + #Nested in a sequence + - CPU: Athlon + GPU: Radeon + OS: Debian + - CPU: Cortex + GPU: PowerVR + OS: Android +``` + +Complex keys start with question mark+space "? ". + +``` + #Nested in a sequence + ? [CPU, GPU]: [Athlon, Radeon] + OS: Debian +``` + +## Scalars + +Scalars are simple values such as integers, strings, timestamps and so on. +There are multiple scalar styles. + +Plain scalars use no quotes, start with the first non-space and end with the +last non-space character: + +``` + scalar: Plain scalar +``` + +Single quoted scalars start and end with single quotes. A single quote is +represented by a pair of single quotes ''. + +``` + scalar: 'Single quoted scalar ending with some spaces ' +``` + +Double quoted scalars support C-style escape sequences. + +``` + scalar: "Double quoted scalar \n with some \\ escape sequences" +``` + +Block scalars are convenient for multi-line values. They start either with +`|` or with `>`. With `|`, the newlines in the scalar are preserved. +With `>`, the newlines between two non-empty lines are removed. + +``` + scalar: | + Newlines are preserved + First line + Second line +``` +``` + scalar: > + Newlines are folded + This is still the first paragraph + + This is the second + paragraph +``` + +## Anchors and aliases + +Anchors and aliases can reduce size of YAML code by allowing you to define a +value once, assign an anchor to it and use alias referring to that anchor +anywhere else you need that value. It is possible to use this to create +recursive data structures and some parsers support this; however, D:YAML does +not (this might change in the future, but it is unlikely). + +``` + Person: &AD + gender: male + name: Arthur Dent + Clone: *AD +``` + +## Tags + +Tags are identifiers that specify data types of YAML nodes. Most default YAML +tags are resolved implicitly, so there is no need to specify them. D:YAML also +supports implicit resolution for custom, user specified tags. + +Explicitly specified tags: + +``` + answer: !!int "42" + name: !!str "Arthur Dent" +``` + +Implicit tags: + +``` + answer: 42 #int + name: Arthur Dent #string +``` + +This table shows D types stored in *yaml.Node* default YAML tags are converted to. +Some of these might change in the future (especially !!map and !!set). + +|YAML tag |D type | +|-----------------------|-----------------------| +|!!null |dyaml.node.YAMLNull | +|!!bool |bool | +|!!int |long | +|!!float |real | +|!!binary |ubyte[] | +|!!timestamp |std.datetime.SysTime | +|!!map, !!omap, !!pairs |dyaml.node.Node.Pair[] | +|!!seq, !!set |dyaml.node.Node[] | +|!!str |string | diff --git a/src/ext_depends/D-YAML/dub.json b/src/ext_depends/D-YAML/dub.json new file mode 100644 index 0000000..07ee17e --- /dev/null +++ b/src/ext_depends/D-YAML/dub.json @@ -0,0 +1,25 @@ +{ + "name": "dyaml", + "description": "YAML parser and emitter", + "authors": [ + "Ferdinand Majerech", + "Cameron \"Herringway\" Ross" + ], + "license": "BSL-1.0", + "dependencies": { + "tinyendian" : "~>0.2.0" + }, + "homepage": "https://github.com/dlang-community/D-YAML", + "copyright": "Copyright © 2011-2018, Ferdinand Majerech", + "subPackages": [ + "examples/constructor", + "examples/getting_started", + "examples/representer", + "examples/resolver", + "examples/tojson", + "examples/yaml_bench", + "examples/yaml_gen", + "examples/yaml_stats", + "testsuite" + ] +} diff --git a/src/ext_depends/D-YAML/examples/constructor/dub.json b/src/ext_depends/D-YAML/examples/constructor/dub.json new file mode 100644 index 0000000..1aca4ee --- /dev/null +++ b/src/ext_depends/D-YAML/examples/constructor/dub.json @@ -0,0 +1,10 @@ +{ + "name": "constructor", + "targetType": "executable", + "sourceFiles": ["main.d"], + "mainSourceFile": "main.d", + "dependencies": + { + "dyaml": { "version" : "*"} + } +} diff --git a/src/ext_depends/D-YAML/examples/constructor/input.yaml b/src/ext_depends/D-YAML/examples/constructor/input.yaml new file mode 100644 index 0000000..8d56926 --- /dev/null +++ b/src/ext_depends/D-YAML/examples/constructor/input.yaml @@ -0,0 +1,8 @@ +scalar-red: !color FF0000 +scalar-orange: !color FFFF00 +mapping-red: !color-mapping {r: 255, g: 0, b: 0} +mapping-orange: + !color-mapping + r: 255 + g: 255 + b: 0 diff --git a/src/ext_depends/D-YAML/examples/constructor/main.d b/src/ext_depends/D-YAML/examples/constructor/main.d new file mode 100644 index 0000000..50826f1 --- /dev/null +++ b/src/ext_depends/D-YAML/examples/constructor/main.d @@ -0,0 +1,91 @@ +import std.stdio; +import std.string; +import dyaml; + +struct Color +{ + ubyte red; + ubyte green; + ubyte blue; + + this(ubyte r, ubyte g, ubyte b) @safe + { + red = r; + green = g; + blue = b; + } + + this(const Node node, string tag) @safe + { + if (tag == "!color-mapping") + { + //Will throw if a value is missing, is not an integer, or is out of range. + red = node["r"].as!ubyte; + green = node["g"].as!ubyte; + blue = node["b"].as!ubyte; + } + else + { + string value = node.as!string; + + if(value.length != 6) + { + throw new Exception("Invalid color: " ~ value); + } + //We don't need to check for uppercase chars this way. + value = value.toLower(); + + //Get value of a hex digit. + uint hex(char c) + { + import std.ascii; + if(!std.ascii.isHexDigit(c)) + { + throw new Exception("Invalid color: " ~ value); + } + + if(std.ascii.isDigit(c)) + { + return c - '0'; + } + return c - 'a' + 10; + } + + red = cast(ubyte)(16 * hex(value[0]) + hex(value[1])); + green = cast(ubyte)(16 * hex(value[2]) + hex(value[3])); + blue = cast(ubyte)(16 * hex(value[4]) + hex(value[5])); + } + } +} + +void main(string[] args) +{ + auto red = Color(255, 0, 0); + auto orange = Color(255, 255, 0); + + string path = "input.yaml"; + if (args.length > 1) + { + path = args[1]; + } + + try + { + auto root = Loader.fromFile(path).load(); + + if(root["scalar-red"].as!Color == red && + root["mapping-red"].as!Color == red && + root["scalar-orange"].as!Color == orange && + root["mapping-orange"].as!Color == orange) + { + writeln("SUCCESS"); + return; + } + } + catch(YAMLException e) + { + writeln(e.msg); + } + + writeln("FAILURE"); +} diff --git a/src/ext_depends/D-YAML/examples/getting_started/dub.json b/src/ext_depends/D-YAML/examples/getting_started/dub.json new file mode 100644 index 0000000..844c006 --- /dev/null +++ b/src/ext_depends/D-YAML/examples/getting_started/dub.json @@ -0,0 +1,10 @@ +{ + "name": "getting-started", + "targetType": "executable", + "sourceFiles": ["main.d"], + "mainSourceFile": "main.d", + "dependencies": + { + "dyaml": { "version" : "*" } + } +} diff --git a/src/ext_depends/D-YAML/examples/getting_started/input.yaml b/src/ext_depends/D-YAML/examples/getting_started/input.yaml new file mode 100644 index 0000000..8b093ae --- /dev/null +++ b/src/ext_depends/D-YAML/examples/getting_started/input.yaml @@ -0,0 +1,2 @@ +Hello World : [Hello, World] +Answer : 42 diff --git a/src/ext_depends/D-YAML/examples/getting_started/main.d b/src/ext_depends/D-YAML/examples/getting_started/main.d new file mode 100644 index 0000000..2cc242c --- /dev/null +++ b/src/ext_depends/D-YAML/examples/getting_started/main.d @@ -0,0 +1,18 @@ +import std.stdio; +import dyaml; + +void main() +{ + //Read the input. + Node root = Loader.fromFile("input.yaml").load(); + + //Display the data read. + foreach(string word; root["Hello World"]) + { + writeln(word); + } + writeln("The answer is ", root["Answer"].as!int); + + //Dump the loaded document to output.yaml. + dumper().dump(File("output.yaml", "w").lockingTextWriter, root); +} diff --git a/src/ext_depends/D-YAML/examples/representer/dub.json b/src/ext_depends/D-YAML/examples/representer/dub.json new file mode 100644 index 0000000..c46c42f --- /dev/null +++ b/src/ext_depends/D-YAML/examples/representer/dub.json @@ -0,0 +1,10 @@ +{ + "name": "representer", + "targetType": "executable", + "sourceFiles": ["main.d"], + "mainSourceFile": "main.d", + "dependencies": + { + "dyaml": { "version" : "*" } + } +} diff --git a/src/ext_depends/D-YAML/examples/representer/main.d b/src/ext_depends/D-YAML/examples/representer/main.d new file mode 100644 index 0000000..18ec4c5 --- /dev/null +++ b/src/ext_depends/D-YAML/examples/representer/main.d @@ -0,0 +1,43 @@ +import std.stdio; +import dyaml; + +struct Color +{ + ubyte red; + ubyte green; + ubyte blue; + + Node opCast(T: Node)() const + { + static immutable hex = "0123456789ABCDEF"; + + //Using the color format from the Constructor example. + string scalar; + foreach(channel; [red, green, blue]) + { + scalar ~= hex[channel / 16]; + scalar ~= hex[channel % 16]; + } + + //Representing as a scalar, with custom tag to specify this data type. + return Node(scalar, "!color"); + } +} + +void main() +{ + try + { + auto dumper = dumper(); + + auto document = Node([Color(255, 0, 0), + Color(0, 255, 0), + Color(0, 0, 255)]); + + dumper.dump(File("output.yaml", "w").lockingTextWriter, document); + } + catch(YAMLException e) + { + writeln(e.msg); + } +} diff --git a/src/ext_depends/D-YAML/examples/resolver/dub.json b/src/ext_depends/D-YAML/examples/resolver/dub.json new file mode 100644 index 0000000..30b55d8 --- /dev/null +++ b/src/ext_depends/D-YAML/examples/resolver/dub.json @@ -0,0 +1,10 @@ +{ + "name": "resolver", + "targetType": "executable", + "sourceFiles": ["main.d"], + "mainSourceFile": "main.d", + "dependencies": + { + "dyaml": { "version" : "*" } + } +} diff --git a/src/ext_depends/D-YAML/examples/resolver/input.yaml b/src/ext_depends/D-YAML/examples/resolver/input.yaml new file mode 100644 index 0000000..99b9a5a --- /dev/null +++ b/src/ext_depends/D-YAML/examples/resolver/input.yaml @@ -0,0 +1,8 @@ +scalar-red: FF0000 +scalar-orange: FFFF00 +mapping-red: !color-mapping {r: 255, g: 0, b: 0} +mapping-orange: + !color-mapping + r: 255 + g: 255 + b: 0 diff --git a/src/ext_depends/D-YAML/examples/resolver/main.d b/src/ext_depends/D-YAML/examples/resolver/main.d new file mode 100644 index 0000000..f3c08a1 --- /dev/null +++ b/src/ext_depends/D-YAML/examples/resolver/main.d @@ -0,0 +1,36 @@ +import std.regex; +import std.stdio; +import dyaml; + +int main(string[] args) +{ + string path = "input.yaml"; + if (args.length > 1) + { + path = args[1]; + } + + try + { + + auto loader = Loader.fromFile("input.yaml"); + loader.resolver.addImplicitResolver("!color", regex("[0-9a-fA-F]{6}"), + "0123456789abcdefABCDEF"); + + auto root = loader.load(); + + if(root["scalar-red"].tag == "!color" && + root["scalar-orange"].tag == "!color") + { + writeln("SUCCESS"); + return 0; + } + } + catch(YAMLException e) + { + writeln(e.msg); + } + + writeln("FAILURE"); + return 1; +} diff --git a/src/ext_depends/D-YAML/examples/tojson/dub.json b/src/ext_depends/D-YAML/examples/tojson/dub.json new file mode 100644 index 0000000..ba014b8 --- /dev/null +++ b/src/ext_depends/D-YAML/examples/tojson/dub.json @@ -0,0 +1,8 @@ +{ + "name": "tojson", + "targetType": "executable", + "dependencies": + { + "dyaml": "*" + } +} diff --git a/src/ext_depends/D-YAML/examples/tojson/source/app.d b/src/ext_depends/D-YAML/examples/tojson/source/app.d new file mode 100644 index 0000000..654274f --- /dev/null +++ b/src/ext_depends/D-YAML/examples/tojson/source/app.d @@ -0,0 +1,54 @@ +module dyaml.tojson; +import std.datetime; +import std.json; +import std.stdio; +import dyaml; + +void main() +{ + auto doc = Loader.fromFile(stdin).load(); + auto json = doc.toJSON; + writeln(json.toPrettyString); +} + +JSONValue toJSON(Node node) +{ + JSONValue output; + final switch (node.type) + { + case NodeType.sequence: + output = JSONValue(string[].init); + foreach (Node seqNode; node) + { + output.array ~= seqNode.toJSON(); + } + break; + case NodeType.mapping: + output = JSONValue(string[string].init); + foreach (Node keyNode, Node valueNode; node) + { + output[keyNode.as!string] = valueNode.toJSON(); + } + break; + case NodeType.string: + output = node.as!string; + break; + case NodeType.integer: + output = node.as!long; + break; + case NodeType.decimal: + output = node.as!real; + break; + case NodeType.boolean: + output = node.as!bool; + break; + case NodeType.timestamp: + output = node.as!SysTime.toISOExtString(); + break; + case NodeType.merge: + case NodeType.null_: + case NodeType.binary: + case NodeType.invalid: + } + return output; +} diff --git a/src/ext_depends/D-YAML/examples/yaml_bench/dub.json b/src/ext_depends/D-YAML/examples/yaml_bench/dub.json new file mode 100644 index 0000000..b4e778f --- /dev/null +++ b/src/ext_depends/D-YAML/examples/yaml_bench/dub.json @@ -0,0 +1,10 @@ +{ + "name": "benchmark", + "targetType": "executable", + "sourceFiles": ["yaml_bench.d"], + "mainSourceFile": "yaml_bench.d", + "dependencies": + { + "dyaml": { "version" : "*" } + } +} diff --git a/src/ext_depends/D-YAML/examples/yaml_bench/yaml_bench.d b/src/ext_depends/D-YAML/examples/yaml_bench/yaml_bench.d new file mode 100644 index 0000000..bb8446e --- /dev/null +++ b/src/ext_depends/D-YAML/examples/yaml_bench/yaml_bench.d @@ -0,0 +1,179 @@ + +module dyaml.yaml_bench; +//Benchmark that loads, and optionally extracts data from and/or emits a YAML file. + +import std.algorithm; +import std.conv; +import std.datetime.systime; +import std.datetime.stopwatch; +import std.file; +import std.getopt; +import std.range; +import std.stdio; +import std.string; +import dyaml; + +///Get data out of every node. +void extract(ref Node document) @safe +{ + void crawl(ref Node root) @safe + { + final switch (root.nodeID) + { + case NodeID.scalar: + switch(root.tag) + { + case "tag:yaml.org,2002:null": auto value = root.as!YAMLNull; break; + case "tag:yaml.org,2002:bool": auto value = root.as!bool; break; + case "tag:yaml.org,2002:int": auto value = root.as!long; break; + case "tag:yaml.org,2002:float": auto value = root.as!real; break; + case "tag:yaml.org,2002:binary": auto value = root.as!(ubyte[]); break; + case "tag:yaml.org,2002:timestamp": auto value = root.as!SysTime; break; + case "tag:yaml.org,2002:str": auto value = root.as!string; break; + default: writeln("Unrecognozed tag: ", root.tag); + } + break; + case NodeID.sequence: + foreach(ref Node node; root) + { + crawl(node); + } + break; + case NodeID.mapping: + foreach(ref Node key, ref Node value; root) + { + crawl(key); + crawl(value); + } + break; + case NodeID.invalid: + assert(0); + } + } + + crawl(document); +} + +void main(string[] args) //@safe +{ + import std.array : array; + bool get = false; + bool dump = false; + bool reload = false; + bool quiet = false; + bool verbose = false; + bool scanOnly = false; + uint runs = 1; + + auto help = getopt( + args, + "get|g", "Extract data from the file (using Node.as()).", &get, + "dump|d", "Dump the loaded data (to YAML_FILE.dump).", &dump, + "runs|r", "Repeat parsing the file NUM times.", &runs, + "reload", "Reload the file from the diskl on every repeat By default,"~ + " the file is loaded to memory once and repeatedly parsed from memory.", &reload, + "quiet|q", "Don't print anything.", &quiet, + "verbose|v", "Print even more.", &verbose, + "scan-only|s", "Do not execute the entire parsing process, only scanning. Overrides '--dump'", &scanOnly + ); + + if (help.helpWanted || (args.length < 2)) + { + defaultGetoptPrinter( + "D:YAML benchmark\n"~ + "Copyright (C) 2011-2018 Ferdinand Majerech, Cameron \"Herringway\" Ross\n"~ + "Usage: yaml_bench [OPTION ...] [YAML_FILE]\n\n"~ + "Loads and optionally extracts data and/or dumps a YAML file.\n", + help.options + ); + return; + } + + string file = args[1]; + + auto stopWatch = StopWatch(AutoStart.yes); + void[] fileInMemory; + if(!reload) { fileInMemory = std.file.read(file); } + void[] fileWorkingCopy = fileInMemory.dup; + auto loadTime = stopWatch.peek(); + stopWatch.reset(); + try + { + // Instead of constructing a resolver/constructor with each Loader, + // construct them once to remove noise when profiling. + auto resolver = Resolver.withDefaultResolvers; + + auto constructTime = stopWatch.peek(); + + Node[] nodes; + + void runLoaderBenchmark() //@safe + { + // Loading the file rewrites the loaded buffer, so if we don't reload from + // disk, we need to use a copy of the originally loaded file. + if(reload) { fileInMemory = std.file.read(file); } + else { fileWorkingCopy[] = fileInMemory[]; } + void[] fileToLoad = reload ? fileInMemory : fileWorkingCopy; + + auto loader = Loader.fromBuffer(fileToLoad); + if(scanOnly) + { + loader.scanBench(); + return; + } + + loader.resolver = resolver; + nodes = loader.array; + } + void runDumpBenchmark() @safe + { + if(dump) + { + dumper().dump(File(file ~ ".dump", "w").lockingTextWriter, nodes); + } + } + void runGetBenchmark() @safe + { + if(get) foreach(ref node; nodes) + { + extract(node); + } + } + auto totalTime = benchmark!(runLoaderBenchmark, runDumpBenchmark, runGetBenchmark)(runs); + if (!quiet) + { + auto enabledOptions = + only( + get ? "Get" : "", + dump ? "Dump" : "", + reload ? "Reload" : "", + scanOnly ? "Scan Only": "" + ).filter!(x => x != ""); + if (!enabledOptions.empty) + { + writefln!"Options enabled: %-(%s, %)"(enabledOptions); + } + if (verbose) + { + if (!reload) + { + writeln("Time to load file: ", loadTime); + } + writeln("Time to set up resolver: ", constructTime); + } + writeln("Runs: ", runs); + foreach(time, func, enabled; lockstep(totalTime[], only("Loader", "Dumper", "Get"), only(true, dump, get))) + { + if (enabled) + { + writeln("Average time spent on ", func, ": ", time / runs); + writeln("Total time spent on ", func, ": ", time); + } + } + } + } + catch(YAMLException e) + { + writeln("ERROR: ", e.msg); + } +} diff --git a/src/ext_depends/D-YAML/examples/yaml_gen/config.yaml b/src/ext_depends/D-YAML/examples/yaml_gen/config.yaml new file mode 100644 index 0000000..5484686 --- /dev/null +++ b/src/ext_depends/D-YAML/examples/yaml_gen/config.yaml @@ -0,0 +1,46 @@ +root-type: map +documents: 2 +complex-keys: false +collection-keys: false +min-nodes-per-document: 4096 +encoding: utf-8 +indent: 4 +text-width: 40 + +#Note: setting collection probabilities too high can lead to stack overflow as +#we end up with extremely deeply nested structures + +string: + probability: 20 + alphabet: " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789ábćčďéěǵǧȟíǐǰḱǩĺľḿńňóǒôäṕŕřśšť" + range: {min: 1, max: 40, dist: cubic} +int: + probability: 10 + range: {min: -10000000, max: 10000000, dist: linear} +float: + probability: 10 + range: {min: -10000000.0, max: 10000000.0, dist: linear} +bool: + probability: 10 +timestamp: + probability: 10 + round-chance: 0.9 + range: {min: 0, max: 1231200000000000000, dist: linear} +binary: + probability: 4 + range: {min: 1, max: 400, dist: quadratic} +map: + probability: 2 + range: {min: 1, max: 20, dist: cubic} +omap: + probability: 1 + range: {min: 1, max: 20, dist: cubic} +pairs: + probability: 1 + range: {min: 1, max: 20, dist: cubic} +seq: + probability: 2 + range: {min: 1, max: 20, dist: cubic} +set: + probability: 1 + range: {min: 1, max: 20, dist: cubic} diff --git a/src/ext_depends/D-YAML/examples/yaml_gen/dub.json b/src/ext_depends/D-YAML/examples/yaml_gen/dub.json new file mode 100644 index 0000000..1f5a2d1 --- /dev/null +++ b/src/ext_depends/D-YAML/examples/yaml_gen/dub.json @@ -0,0 +1,10 @@ +{ + "name": "yaml_gen", + "targetType": "executable", + "sourceFiles": ["yaml_gen.d"], + "mainSourceFile": "yaml_gen.d", + "dependencies": + { + "dyaml": { "version" : "*" } + } +} diff --git a/src/ext_depends/D-YAML/examples/yaml_gen/yaml_gen.d b/src/ext_depends/D-YAML/examples/yaml_gen/yaml_gen.d new file mode 100644 index 0000000..b970c31 --- /dev/null +++ b/src/ext_depends/D-YAML/examples/yaml_gen/yaml_gen.d @@ -0,0 +1,316 @@ + +///Random YAML generator. Used to generate benchmarking inputs. + +import std.algorithm; +import std.conv; +import std.datetime; +import std.math; +import std.random; +import std.stdio; +import std.string; +import dyaml; + + +Node config; +Node function(bool)[string] generators; +auto typesScalar = ["string", "int", "float", "bool", "timestamp", "binary"]; +auto typesScalarKey = ["string", "int", "float", "timestamp"]; +auto typesCollection = ["map","omap", "pairs", "seq", "set"]; +ulong minNodesDocument; +ulong totalNodes; + +static this() +{ + generators["string"] = &genString; + generators["int"] = &genInt; + generators["float"] = &genFloat; + generators["bool"] = &genBool; + generators["timestamp"] = &genTimestamp; + generators["binary"] = &genBinary; + generators["map"] = &genMap; + generators["omap"] = &genOmap; + generators["pairs"] = &genPairs; + generators["seq"] = &genSeq; + generators["set"] = &genSet; +} + +real randomNormalized(const string distribution = "linear") +{ + auto generator = Random(unpredictableSeed()); + const r = uniform!"[]"(0.0L, 1.0L, generator); + switch(distribution) + { + case "linear": + return r; + case "quadratic": + return r * r; + case "cubic": + return r * r * r; + default: + writeln("Unknown random distribution: ", distribution, + ", falling back to linear"); + return randomNormalized("linear"); + } +} + +long randomLong(const long min, const long max, const string distribution = "linear") +{ + return min + cast(long)round((max - min) * randomNormalized(distribution)); +} + +real randomReal(const real min, const real max, const string distribution = "linear") +{ + return min + (max - min) * randomNormalized(distribution); +} + +dchar randomChar(const dstring chars) +{ + return chars[randomLong(0, chars.length - 1)]; +} + +string randomType(string[] types) +{ + auto probabilities = new uint[types.length]; + foreach(index, type; types) + { + probabilities[index] = config[type]["probability"].as!uint; + } + return types[dice(probabilities)]; +} + +Node genString(bool root = false) +{ + auto range = config["string"]["range"]; + + auto alphabet = config["string"]["alphabet"].as!dstring; + + const chars = randomLong(range["min"].as!uint, range["max"].as!uint, + range["dist"].as!string); + + dchar[] result = new dchar[chars]; + result[0] = randomChar(alphabet); + foreach(i; 1 .. chars) + { + result[i] = randomChar(alphabet); + } + + return Node(result.to!string); +} + +Node genInt(bool root = false) +{ + auto range = config["int"]["range"]; + + const result = randomLong(range["min"].as!int, range["max"].as!int, + range["dist"].as!string); + + return Node(result); +} + +Node genFloat(bool root = false) +{ + auto range = config["float"]["range"]; + + const result = randomReal(range["min"].as!real, range["max"].as!real, + range["dist"].as!string); + + return Node(result); +} + +Node genBool(bool root = false) +{ + return Node([true, false][randomLong(0, 1)]); +} + +Node genTimestamp(bool root = false) +{ + auto range = config["timestamp"]["range"]; + + auto hnsecs = randomLong(range["min"].as!ulong, range["max"].as!ulong, + range["dist"].as!string); + + if(randomNormalized() <= config["timestamp"]["round-chance"].as!real) + { + hnsecs -= hnsecs % 10000000; + } + + return Node(SysTime(hnsecs)); +} + +Node genBinary(bool root = false) +{ + auto range = config["binary"]["range"]; + + const bytes = randomLong(range["min"].as!uint, range["max"].as!uint, + range["dist"].as!string); + + ubyte[] result = new ubyte[bytes]; + foreach(i; 0 .. bytes) + { + result[i] = cast(ubyte)randomLong(0, 255); + } + + return Node(result); +} + +Node nodes(const bool root, Node range, const string tag, const bool set = false) +{ + auto types = config["collection-keys"].as!bool ? typesCollection : []; + types ~= (set ? typesScalarKey : typesScalar); + + Node[] nodes; + if(root) + { + while(!(totalNodes >= minNodesDocument)) + { + nodes.assumeSafeAppend; + nodes ~= generateNode(randomType(types)); + } + } + else + { + const elems = randomLong(range["min"].as!uint, range["max"].as!uint, + range["dist"].as!string); + + nodes = new Node[elems]; + foreach(i; 0 .. elems) + { + nodes[i] = generateNode(randomType(types)); + } + } + + return Node(nodes, tag); +} + +Node genSeq(bool root = false) +{ + return nodes(root, config["seq"]["range"], "tag:yaml.org,2002:seq"); +} + +Node genSet(bool root = false) +{ + return nodes(root, config["seq"]["range"], "tag:yaml.org,2002:set", true); +} + +Node pairs(bool root, bool complex, Node range, string tag) +{ + Node[] keys, values; + + if(root) + { + while(!(totalNodes >= minNodesDocument)) + { + const key = generateNode(randomType(typesScalarKey ~ (complex ? typesCollection : []))); + // Maps can't contain duplicate keys + if(tag.endsWith("map") && keys.canFind(key)) { continue; } + keys.assumeSafeAppend; + values.assumeSafeAppend; + keys ~= key; + values ~= generateNode(randomType(typesScalar ~ typesCollection)); + } + } + else + { + const pairs = randomLong(range["min"].as!uint, range["max"].as!uint, + range["dist"].as!string); + + keys = new Node[pairs]; + values = new Node[pairs]; + outer: foreach(i; 0 .. pairs) + { + auto key = generateNode(randomType(typesScalarKey ~ (complex ? typesCollection : []))); + // Maps can't contain duplicate keys + while(tag.endsWith("map") && keys[0 .. i].canFind(key)) + { + key = generateNode(randomType(typesScalarKey ~ (complex ? typesCollection : []))); + } + keys[i] = key; + values[i] = generateNode(randomType(typesScalar ~ typesCollection)); + } + } + + return Node(keys, values, tag); +} + +Node genMap(bool root = false) +{ + Node range = config["map"]["range"]; + const complex = config["complex-keys"].as!bool; + + return pairs(root, complex, range, "tag:yaml.org,2002:map"); +} + +Node genOmap(bool root = false) +{ + Node range = config["omap"]["range"]; + const complex = config["complex-keys"].as!bool; + + return pairs(root, complex, range, "tag:yaml.org,2002:omap"); +} + +Node genPairs(bool root = false) +{ + Node range = config["pairs"]["range"]; + const complex = config["complex-keys"].as!bool; + + return pairs(root, complex, range, "tag:yaml.org,2002:pairs"); +} + +Node generateNode(const string type, bool root = false) +{ + ++totalNodes; + return generators[type](root); +} + +Node[] generate(const string configFileName) +{ + config = Loader.fromFile(configFileName).load(); + + minNodesDocument = config["min-nodes-per-document"].as!long; + + Node[] result; + foreach(i; 0 .. config["documents"].as!uint) + { + result ~= generateNode(config["root-type"].as!string, true); + totalNodes = 0; + } + + return result; +} + + +void main(string[] args) +{ + //Help message. + if(args.length == 1) + { + writeln("Usage: yaml_gen FILE [CONFIG_FILE]\n"); + writeln("Generates a random YAML file and writes it to FILE."); + writeln("If provided, CONFIG_FILE overrides the default config file."); + return; + } + + string configFile = args.length >= 3 ? args[2] : "config.yaml"; + + try + { + //Generate and dump the nodes. + Node[] generated = generate(configFile); + + auto dumper = dumper(); + auto encoding = config["encoding"]; + + dumper.indent = config["indent"].as!uint; + dumper.textWidth = config["text-width"].as!uint; + switch(encoding.as!string) + { + case "utf-16": dumper.dump!wchar(File(args[1], "w").lockingTextWriter, generated); break; + case "utf-32": dumper.dump!dchar(File(args[1], "w").lockingTextWriter, generated); break; + default: dumper.dump!char(File(args[1], "w").lockingTextWriter, generated); break; + } + } + catch(YAMLException e) + { + writeln("ERROR: ", e.msg); + } +} diff --git a/src/ext_depends/D-YAML/examples/yaml_stats/dub.json b/src/ext_depends/D-YAML/examples/yaml_stats/dub.json new file mode 100644 index 0000000..c86f091 --- /dev/null +++ b/src/ext_depends/D-YAML/examples/yaml_stats/dub.json @@ -0,0 +1,10 @@ +{ + "name": "yaml_stats", + "targetType": "executable", + "sourceFiles": ["yaml_stats.d"], + "mainSourceFile": "yaml_stats.d", + "dependencies": + { + "dyaml": { "version" : "*" } + } +} diff --git a/src/ext_depends/D-YAML/examples/yaml_stats/small.yaml b/src/ext_depends/D-YAML/examples/yaml_stats/small.yaml new file mode 100644 index 0000000..4f5c0ea --- /dev/null +++ b/src/ext_depends/D-YAML/examples/yaml_stats/small.yaml @@ -0,0 +1,4 @@ +- 1 +- 2 : 'a' + 3 : 'b' +- 4 : [1.0, 2.1, 3.2] diff --git a/src/ext_depends/D-YAML/examples/yaml_stats/yaml_stats.d b/src/ext_depends/D-YAML/examples/yaml_stats/yaml_stats.d new file mode 100644 index 0000000..b3f6c17 --- /dev/null +++ b/src/ext_depends/D-YAML/examples/yaml_stats/yaml_stats.d @@ -0,0 +1,106 @@ + +///Example D:YAML application that displays statistics about YAML documents. + +import std.stdio; +import std.string; +import dyaml; + + +///Collects statistics about a YAML document and returns them as string. +string statistics(ref Node document) +{ + size_t nodes; + size_t scalars, sequences, mappings; + size_t seqItems, mapPairs; + + size_t[string] tags; + + void crawl(ref Node root) + { + ++nodes; + if((root.tag in tags) is null) + { + tags[root.tag] = 0; + } + ++tags[root.tag]; + final switch (root.nodeID) + { + case NodeID.scalar: + ++scalars; + return; + case NodeID.sequence: + ++sequences; + seqItems += root.length; + foreach(ref Node node; root) + { + crawl(node); + } + return; + case NodeID.mapping: + ++mappings; + mapPairs += root.length; + foreach(ref Node key, ref Node value; root) + { + crawl(key); + crawl(value); + } + return; + case NodeID.invalid: + assert(0); + } + } + + crawl(document); + + string tagStats = "\nTag statistics:\n"; + foreach(tag, count; tags) + { + tagStats ~= format("\n%s : %s", tag, count); + } + + return format( "\nNodes: %s" ~ + "\n\nScalars: %s" ~ + "\nSequences: %s" ~ + "\nMappings: %s" ~ + "\n\nAverage sequence length: %s" ~ + "\nAverage mapping length: %s" ~ + "\n\n%s", + nodes, scalars, sequences, mappings, + sequences == 0.0 ? 0.0 : cast(real)seqItems / sequences, + mappings == 0.0 ? 0.0 : cast(real)mapPairs / mappings, + tagStats); +} + +void main(string[] args) +{ + //Help message + if(args.length == 1) + { + writeln("Usage: yaml_stats [YAML_FILE ...]\n"); + writeln("Analyzes YAML files with provided filenames and displays statistics."); + return; + } + + //Print stats about every document in every file. + foreach(file; args[1 .. $]) + { + writeln("\nFile ", file); + writeln("------------------------------------------------------------"); + try + { + auto loader = Loader.fromFile(file); + + size_t idx = 0; + foreach(ref document; loader) + { + writeln("\nDocument ", idx++); + writeln("----------------------------------------"); + writeln(statistics(document)); + } + } + catch(YAMLException e) + { + writeln("ERROR: ", e.msg); + } + } +} diff --git a/src/ext_depends/D-YAML/hmod.cfg b/src/ext_depends/D-YAML/hmod.cfg new file mode 100644 index 0000000..41badb2 --- /dev/null +++ b/src/ext_depends/D-YAML/hmod.cfg @@ -0,0 +1,123 @@ + +# This file contains configuration options for harbored-mod (hmod). +# +# By default, hmod loads configuration from file 'hmod.cfg' in the directory from where +# hmod is running, if such file exists. These configuration options can also be passed +# as command-line options for hmod, overriding contents of the config file, if any, +# with the exception of options that allow multiple values (such as 'exclude' or +# 'macros') where the values specified as command-line options are *added* to the values +# in config file. + + + +# Source code files or directories to document. Specify more than once to document more +# files/directories, e.g: +# +# sources = ./sources +# sources = ./thirdparty +# +# This will document both the source code in the ./source/ and ./thirdparty/ directories. +# +# For DUB (http://code.dlang.org) projects, './sources' is usually a good setting here. +source = ./source/dyaml + + +# Directory where the generated documentation will be written. +output-directory = ./doc/html/api + + +# Modules or packages to exclude from generated documentation. Specify more than once to +# exclude more modules/packages, e.g: +# +# exclude = tharsis.util +# exclude = tharsis.entity.gamestate +# +# This will exclude both the package (or module) tharsis.util and module (or package) +# tharsis.entity.gamestate . + +exclude = dyaml.all +exclude = dyaml.anchor +exclude = dyaml.composer +exclude = dyaml.emitter +exclude = dyaml.encoding +exclude = dyaml.escapes +exclude = dyaml.event +exclude = dyaml.fastcharsearch +exclude = dyaml.flags +exclude = dyaml.nogcutil +exclude = dyaml.parser +exclude = dyaml.queue +exclude = dyaml.reader +exclude = dyaml.scanner +exclude = dyaml.serializer +exclude = dyaml.streamcompat +exclude = dyaml.tag +exclude = dyaml.tagdirective +exclude = dyaml.testcommon +exclude = dyaml.testcompare +exclude = dyaml.testconstructor +exclude = dyaml.testemitter +exclude = dyaml.testerrors +exclude = dyaml.testinputoutput +exclude = dyaml.testreader +exclude = dyaml.testrepresenter +exclude = dyaml.testresolver +exclude = dyaml.testtokens +exclude = dyaml.token +exclude = dyaml.unused +exclude = dyaml.zerostring + +# DDoc+markdown source of the main page of your documentation. Currently the main page is +# blank by default; this can be used to fill it with something useful. + +index = + + +# DDoc+markdown source of additional content to add to the table of contents sidebar. +# Useful e.g. to add links to tutorials. + +toc-additional = + + +# CSS file to use for styling. Can be used to replace the default style. +# To create a new style, you can start by generating the default style file with +# 'hmod --generate-css CSS_OUT_FILE' (CSS_OUT_FILE is name the generated file will have) +# and then modifying the CSS to get the desired style. + +css = + + +# File to load DDoc macros from. Can be used to override builtin macros or add new ones. +# Can be specified more than once to use multiple macro files, e.g.: +# +# macros = macros.ddoc +# macros = moremacros.ddoc + + +macros = + +# Additional config file to load, if needed. Configuration options in specified file will +# override or add to any options specified before this line, and will be overridden by +# any options after this line. Think of it as including the config file in this file. + +config = + + + +#--------------------------------------------------------------------------- +# Configuration options **only** useful for harbored-mod testing +#--------------------------------------------------------------------------- +# Uncommenting these will result in printing help information; only useful for testing. +# +# # Print help message. +# +# help +# +# +# # Generate default CSS file and write it to specified file. +# generate-css = hmod-style.css +# +# +# # Generate default config file and write it to 'hmod.cfg'. +# +# generate-cfg diff --git a/src/ext_depends/D-YAML/meson.build b/src/ext_depends/D-YAML/meson.build new file mode 100644 index 0000000..68d17c7 --- /dev/null +++ b/src/ext_depends/D-YAML/meson.build @@ -0,0 +1,70 @@ +project('D-YAML', 'd', + meson_version: '>=0.40.0', + subproject_dir: 'contrib', + version: '0.8.0' +) + +project_soversion = '0' + +src_dir = include_directories('source/') +pkgc = import('pkgconfig') + +dyaml_src = [ + 'source/dyaml/composer.d', + 'source/dyaml/constructor.d', + 'source/dyaml/dumper.d', + 'source/dyaml/emitter.d', + 'source/dyaml/encoding.d', + 'source/dyaml/escapes.d', + 'source/dyaml/event.d', + 'source/dyaml/exception.d', + 'source/dyaml/linebreak.d', + 'source/dyaml/loader.d', + 'source/dyaml/node.d', + 'source/dyaml/package.d', + 'source/dyaml/parser.d', + 'source/dyaml/queue.d', + 'source/dyaml/reader.d', + 'source/dyaml/representer.d', + 'source/dyaml/resolver.d', + 'source/dyaml/scanner.d', + 'source/dyaml/serializer.d', + 'source/dyaml/style.d', + 'source/dyaml/tagdirective.d', + 'source/dyaml/test/common.d', + 'source/dyaml/test/compare.d', + 'source/dyaml/test/constructor.d', + 'source/dyaml/test/emitter.d', + 'source/dyaml/test/errors.d', + 'source/dyaml/test/inputoutput.d', + 'source/dyaml/test/reader.d', + 'source/dyaml/test/representer.d', + 'source/dyaml/test/resolver.d', + 'source/dyaml/test/tokens.d', + 'source/dyaml/token.d' +] +install_subdir('source/dyaml', install_dir: 'include/d/yaml/') + +tinyendian_dep = dependency('tinyendian', version: '>=0.2.0', fallback: ['tinyendian', 'tinyendian_dep']) + +dyaml_lib = library('dyaml', + [dyaml_src], + include_directories: [src_dir], + dependencies: [tinyendian_dep], + install: true, + version: meson.project_version(), + soversion: project_soversion +) +pkgc.generate(name: 'dyaml', + libraries: dyaml_lib, + subdirs: 'd/yaml/', + version: meson.project_version(), + description: 'YAML parser and emitter for the D programming language.' +) + +# Make D-YAML easy to use as subproject +dyaml_dep = declare_dependency( + link_with: dyaml_lib, + include_directories: [src_dir], + dependencies: [tinyendian_dep] +) diff --git a/src/ext_depends/D-YAML/source/dyaml/composer.d b/src/ext_depends/D-YAML/source/dyaml/composer.d new file mode 100644 index 0000000..c000b02 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/composer.d @@ -0,0 +1,375 @@ + +// 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) + +/** + * Composes nodes from YAML events provided by parser. + * Code based on PyYAML: http://www.pyyaml.org + */ +module dyaml.composer; + +import core.memory; + +import std.algorithm; +import std.array; +import std.conv; +import std.exception; +import std.range; +import std.typecons; + +import dyaml.constructor; +import dyaml.event; +import dyaml.exception; +import dyaml.node; +import dyaml.parser; +import dyaml.resolver; + + +package: +/** + * Exception thrown at composer errors. + * + * See_Also: MarkedYAMLException + */ +class ComposerException : MarkedYAMLException +{ + mixin MarkedExceptionCtors; +} + +///Composes YAML documents from events provided by a Parser. +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 + ///a pair array, as the inner levels are processed as a + ///part of the outer levels. Used as a stack. + Appender!(Node.Pair[])[] pairAppenders_; + ///Used to reduce allocations when creating node arrays. + /// + ///We need one appender for each nesting level that involves + ///a node array, as the inner levels are processed as a + ///part of the outer levels. Used as a stack. + Appender!(Node[])[] nodeAppenders_; + + public: + /** + * Construct a composer. + * + * Params: parser = Parser to provide YAML events. + * resolver = Resolver to resolve tags (data types). + */ + this(Parser parser, Resolver resolver) @safe + { + parser_ = parser; + resolver_ = resolver; + } + + /** + * Determine if there are any nodes left. + * + * Must be called before loading as it handles the stream start event. + */ + bool checkNode() @safe + { + // If next event is stream start, skip it + parser_.skipOver!"a.id == b"(EventID.streamStart); + + //True if there are more documents available. + 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, + "Trying to get a node from Composer when there is no node to " ~ + "get. use checkNode() to determine if there is a node."); + + return composeDocument(); + } + + private: + + void skipExpected(const EventID id) @safe + { + const foundExpected = parser_.skipOver!"a.id == b"(id); + assert(foundExpected, text("Expected ", id, " not found.")); + } + ///Ensure that appenders for specified nesting levels exist. + /// + ///Params: pairAppenderLevel = Current level in the pair appender stack. + /// nodeAppenderLevel = Current level the node appender stack. + void ensureAppendersExist(const uint pairAppenderLevel, const uint nodeAppenderLevel) + @safe + { + while(pairAppenders_.length <= pairAppenderLevel) + { + pairAppenders_ ~= appender!(Node.Pair[])(); + } + while(nodeAppenders_.length <= nodeAppenderLevel) + { + nodeAppenders_ ~= appender!(Node[])(); + } + } + + ///Compose a YAML document and return its root node. + Node composeDocument() @safe + { + skipExpected(EventID.documentStart); + + //Compose the root node. + Node node = composeNode(0, 0); + + skipExpected(EventID.documentEnd); + + anchors_.destroy(); + return node; + } + + /// Compose a node. + /// + /// Params: pairAppenderLevel = Current level of the pair appender stack. + /// nodeAppenderLevel = Current level of the node appender stack. + Node composeNode(const uint pairAppenderLevel, const uint nodeAppenderLevel) @safe + { + if(parser_.front.id == EventID.alias_) + { + const event = parser_.front; + parser_.popFront(); + const anchor = event.anchor; + enforce((anchor in anchors_) !is null, + new ComposerException("Found undefined alias: " ~ anchor, + event.startMark)); + + //If the node referenced by the anchor is uninitialized, + //it's not finished, i.e. we're currently composing it + //and trying to use it recursively here. + enforce(anchors_[anchor] != Node(), + new ComposerException("Found recursive alias: " ~ anchor, + event.startMark)); + + return anchors_[anchor]; + } + + const event = parser_.front; + const anchor = event.anchor; + if((anchor !is null) && (anchor in anchors_) !is null) + { + throw new ComposerException("Found duplicate anchor: " ~ anchor, + event.startMark); + } + + Node result; + //Associate the anchor, if any, with an uninitialized node. + //used to detect duplicate and recursive anchors. + if(anchor !is null) + { + anchors_[anchor] = Node(); + } + + switch (parser_.front.id) + { + case EventID.scalar: + result = composeScalarNode(); + break; + case EventID.sequenceStart: + result = composeSequenceNode(pairAppenderLevel, nodeAppenderLevel); + break; + case EventID.mappingStart: + result = composeMappingNode(pairAppenderLevel, nodeAppenderLevel); + break; + default: assert(false, "This code should never be reached"); + } + + if(anchor !is null) + { + anchors_[anchor] = result; + } + return result; + } + + ///Compose a scalar node. + Node composeScalarNode() @safe + { + 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, + event.value); + node.scalarStyle = event.scalarStyle; + + return node; + } + + /// Compose a sequence node. + /// + /// Params: pairAppenderLevel = Current level of the pair appender stack. + /// nodeAppenderLevel = Current level of the node appender stack. + Node composeSequenceNode(const uint pairAppenderLevel, const uint nodeAppenderLevel) + @safe + { + ensureAppendersExist(pairAppenderLevel, nodeAppenderLevel); + auto nodeAppender = &(nodeAppenders_[nodeAppenderLevel]); + + const startEvent = parser_.front; + parser_.popFront(); + const tag = resolver_.resolve(NodeID.sequence, startEvent.tag, null, + startEvent.implicit); + + while(parser_.front.id != EventID.sequenceEnd) + { + nodeAppender.put(composeNode(pairAppenderLevel, nodeAppenderLevel + 1)); + } + + Node node = constructNode(startEvent.startMark, parser_.front.endMark, + tag, nodeAppender.data.dup); + node.collectionStyle = startEvent.collectionStyle; + parser_.popFront(); + nodeAppender.clear(); + + return node; + } + + /** + * Flatten a node, merging it with nodes referenced through YAMLMerge data type. + * + * Node must be a mapping or a sequence of mappings. + * + * Params: root = Node to flatten. + * startMark = Start position of the node. + * endMark = End position of the node. + * pairAppenderLevel = Current level of the pair appender stack. + * nodeAppenderLevel = Current level of the node appender stack. + * + * Returns: Flattened mapping as pairs. + */ + Node.Pair[] flatten(ref Node root, const Mark startMark, const Mark endMark, + const uint pairAppenderLevel, const uint nodeAppenderLevel) @safe + { + void error(Node node) + { + //this is Composer, but the code is related to Constructor. + throw new ConstructorException("While constructing a mapping, " ~ + "expected a mapping or a list of " ~ + "mappings for merging, but found: " ~ + text(node.type) ~ + " NOTE: line/column shows topmost parent " ~ + "to which the content is being merged", + startMark, endMark); + } + + ensureAppendersExist(pairAppenderLevel, nodeAppenderLevel); + auto pairAppender = &(pairAppenders_[pairAppenderLevel]); + + final switch (root.nodeID) + { + case NodeID.mapping: + Node[] toMerge; + toMerge.reserve(root.length); + foreach (ref Node key, ref Node value; root) + { + if(key.type == NodeType.merge) + { + toMerge ~= value; + } + else + { + auto temp = Node.Pair(key, value); + pairAppender.put(temp); + } + } + foreach (node; toMerge) + { + pairAppender.put(flatten(node, startMark, endMark, + pairAppenderLevel + 1, nodeAppenderLevel)); + } + break; + case NodeID.sequence: + foreach (ref Node node; root) + { + if (node.nodeID != NodeID.mapping) + { + error(node); + } + pairAppender.put(flatten(node, startMark, endMark, + pairAppenderLevel + 1, nodeAppenderLevel)); + } + break; + case NodeID.scalar: + case NodeID.invalid: + error(root); + break; + } + + auto flattened = pairAppender.data.dup; + pairAppender.clear(); + + return flattened; + } + + /// Compose a mapping node. + /// + /// Params: pairAppenderLevel = Current level of the pair appender stack. + /// nodeAppenderLevel = Current level of the node appender stack. + Node composeMappingNode(const uint pairAppenderLevel, const uint nodeAppenderLevel) + @safe + { + ensureAppendersExist(pairAppenderLevel, nodeAppenderLevel); + 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) + { + 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); + } + //Not YAMLMerge, just add the pair. + else + { + pairAppender.put(pair); + } + } + foreach(node; toMerge) + { + merge(*pairAppender, flatten(node[0], startEvent.startMark, node[1], + pairAppenderLevel + 1, nodeAppenderLevel)); + } + auto numUnique = pairAppender.data.dup + .sort!((x,y) => x.key > y.key) + .uniq!((x,y) => x.key == y.key) + .walkLength; + enforce(numUnique == pairAppender.data.length, + new ComposerException("Duplicate key found in mapping", parser_.front.startMark)); + + Node node = constructNode(startEvent.startMark, parser_.front.endMark, + tag, pairAppender.data.dup); + node.collectionStyle = startEvent.collectionStyle; + parser_.popFront(); + + pairAppender.clear(); + return node; + } +} diff --git a/src/ext_depends/D-YAML/source/dyaml/constructor.d b/src/ext_depends/D-YAML/source/dyaml/constructor.d new file mode 100644 index 0000000..bc1d75c --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/constructor.d @@ -0,0 +1,611 @@ + +// 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) + +/** + * Class that processes YAML mappings, sequences and scalars into nodes. + * This can be used to add custom data types. A tutorial can be found + * $(LINK2 https://dlang-community.github.io/D-YAML/, here). + */ +module dyaml.constructor; + + +import std.array; +import std.algorithm; +import std.base64; +import std.container; +import std.conv; +import std.datetime; +import std.exception; +import std.regex; +import std.string; +import std.typecons; +import std.utf; + +import dyaml.node; +import dyaml.exception; +import dyaml.style; + +package: + +// Exception thrown at constructor errors. +class ConstructorException : YAMLException +{ + /// Construct a ConstructorException. + /// + /// Params: msg = Error message. + /// start = Start position of the error context. + /// end = End position of the error context. + this(string msg, Mark start, Mark end, string file = __FILE__, size_t line = __LINE__) + @safe pure nothrow + { + super(msg ~ "\nstart: " ~ start.toString() ~ "\nend: " ~ end.toString(), + file, line); + } +} + +/** Constructs YAML values. + * + * Each YAML scalar, sequence or mapping has a tag specifying its data type. + * Constructor uses user-specifyable functions to create a node of desired + * data type from a scalar, sequence or mapping. + * + * + * Each of these functions is associated with a tag, and can process either + * a scalar, a sequence, or a mapping. The constructor passes each value to + * the function with corresponding tag, which then returns the resulting value + * that can be stored in a node. + * + * If a tag is detected with no known constructor function, it is considered an error. + */ +/* + * Construct a node. + * + * Params: start = Start position of the node. + * end = End position of the node. + * tag = Tag (data type) of the node. + * value = Value to construct node from (string, nodes or pairs). + * style = Style of the node (scalar or collection style). + * + * Returns: Constructed node. + */ +Node constructNode(T)(const Mark start, const Mark end, const string tag, + T value) @safe + if((is(T : string) || is(T == Node[]) || is(T == Node.Pair[]))) +{ + Node newNode; + try + { + switch(tag) + { + case "tag:yaml.org,2002:null": + newNode = Node(YAMLNull(), tag); + break; + case "tag:yaml.org,2002:bool": + static if(is(T == string)) + { + newNode = Node(constructBool(value), tag); + break; + } + else throw new Exception("Only scalars can be bools"); + case "tag:yaml.org,2002:int": + static if(is(T == string)) + { + newNode = Node(constructLong(value), tag); + break; + } + else throw new Exception("Only scalars can be ints"); + case "tag:yaml.org,2002:float": + static if(is(T == string)) + { + newNode = Node(constructReal(value), tag); + break; + } + else throw new Exception("Only scalars can be floats"); + case "tag:yaml.org,2002:binary": + static if(is(T == string)) + { + newNode = Node(constructBinary(value), tag); + break; + } + else throw new Exception("Only scalars can be binary data"); + case "tag:yaml.org,2002:timestamp": + static if(is(T == string)) + { + newNode = Node(constructTimestamp(value), tag); + break; + } + else throw new Exception("Only scalars can be timestamps"); + case "tag:yaml.org,2002:str": + static if(is(T == string)) + { + newNode = Node(constructString(value), tag); + break; + } + else throw new Exception("Only scalars can be strings"); + case "tag:yaml.org,2002:value": + static if(is(T == string)) + { + newNode = Node(constructString(value), tag); + break; + } + else throw new Exception("Only scalars can be values"); + case "tag:yaml.org,2002:omap": + static if(is(T == Node[])) + { + newNode = Node(constructOrderedMap(value), tag); + break; + } + else throw new Exception("Only sequences can be ordered maps"); + case "tag:yaml.org,2002:pairs": + static if(is(T == Node[])) + { + newNode = Node(constructPairs(value), tag); + break; + } + else throw new Exception("Only sequences can be pairs"); + case "tag:yaml.org,2002:set": + static if(is(T == Node.Pair[])) + { + newNode = Node(constructSet(value), tag); + break; + } + else throw new Exception("Only mappings can be sets"); + case "tag:yaml.org,2002:seq": + static if(is(T == Node[])) + { + newNode = Node(constructSequence(value), tag); + break; + } + else throw new Exception("Only sequences can be sequences"); + case "tag:yaml.org,2002:map": + static if(is(T == Node.Pair[])) + { + newNode = Node(constructMap(value), tag); + break; + } + else throw new Exception("Only mappings can be maps"); + case "tag:yaml.org,2002:merge": + newNode = Node(YAMLMerge(), tag); + break; + default: + newNode = Node(value, tag); + break; + } + } + catch(Exception e) + { + throw new ConstructorException("Error constructing " ~ typeid(T).toString() + ~ ":\n" ~ e.msg, start, end); + } + + newNode.startMark_ = start; + + return newNode; +} + +private: +// Construct a boolean _node. +bool constructBool(const string str) @safe +{ + string value = str.toLower(); + if(value.among!("yes", "true", "on")){return true;} + if(value.among!("no", "false", "off")){return false;} + throw new Exception("Unable to parse boolean value: " ~ value); +} + +// Construct an integer (long) _node. +long constructLong(const string str) @safe +{ + string value = str.replace("_", ""); + const char c = value[0]; + const long sign = c != '-' ? 1 : -1; + if(c == '-' || c == '+') + { + value = value[1 .. $]; + } + + enforce(value != "", new Exception("Unable to parse float value: " ~ value)); + + long result; + try + { + //Zero. + if(value == "0") {result = cast(long)0;} + //Binary. + else if(value.startsWith("0b")){result = sign * to!int(value[2 .. $], 2);} + //Hexadecimal. + else if(value.startsWith("0x")){result = sign * to!int(value[2 .. $], 16);} + //Octal. + else if(value[0] == '0') {result = sign * to!int(value, 8);} + //Sexagesimal. + else if(value.canFind(":")) + { + long val; + long base = 1; + foreach_reverse(digit; value.split(":")) + { + val += to!long(digit) * base; + base *= 60; + } + result = sign * val; + } + //Decimal. + else{result = sign * to!long(value);} + } + catch(ConvException e) + { + throw new Exception("Unable to parse integer value: " ~ value); + } + + return result; +} +@safe unittest +{ + string canonical = "685230"; + string decimal = "+685_230"; + string octal = "02472256"; + string hexadecimal = "0x_0A_74_AE"; + string binary = "0b1010_0111_0100_1010_1110"; + string sexagesimal = "190:20:30"; + + assert(685230 == constructLong(canonical)); + assert(685230 == constructLong(decimal)); + assert(685230 == constructLong(octal)); + assert(685230 == constructLong(hexadecimal)); + assert(685230 == constructLong(binary)); + assert(685230 == constructLong(sexagesimal)); +} + +// Construct a floating point (real) _node. +real constructReal(const string str) @safe +{ + string value = str.replace("_", "").toLower(); + const char c = value[0]; + const real sign = c != '-' ? 1.0 : -1.0; + if(c == '-' || c == '+') + { + value = value[1 .. $]; + } + + enforce(value != "" && value != "nan" && value != "inf" && value != "-inf", + new Exception("Unable to parse float value: " ~ value)); + + real result; + try + { + //Infinity. + if (value == ".inf"){result = sign * real.infinity;} + //Not a Number. + else if(value == ".nan"){result = real.nan;} + //Sexagesimal. + else if(value.canFind(":")) + { + real val = 0.0; + real base = 1.0; + foreach_reverse(digit; value.split(":")) + { + val += to!real(digit) * base; + base *= 60.0; + } + result = sign * val; + } + //Plain floating point. + else{result = sign * to!real(value);} + } + catch(ConvException e) + { + throw new Exception("Unable to parse float value: \"" ~ value ~ "\""); + } + + return result; +} +@safe unittest +{ + bool eq(real a, real b, real epsilon = 0.2) @safe + { + return a >= (b - epsilon) && a <= (b + epsilon); + } + + string canonical = "6.8523015e+5"; + string exponential = "685.230_15e+03"; + string fixed = "685_230.15"; + string sexagesimal = "190:20:30.15"; + string negativeInf = "-.inf"; + string NaN = ".NaN"; + + assert(eq(685230.15, constructReal(canonical))); + assert(eq(685230.15, constructReal(exponential))); + assert(eq(685230.15, constructReal(fixed))); + assert(eq(685230.15, constructReal(sexagesimal))); + assert(eq(-real.infinity, constructReal(negativeInf))); + assert(to!string(constructReal(NaN)) == "nan"); +} + +// Construct a binary (base64) _node. +ubyte[] constructBinary(const string value) @safe +{ + import std.ascii : newline; + import std.array : array; + + // For an unknown reason, this must be nested to work (compiler bug?). + try + { + return Base64.decode(value.representation.filter!(c => !newline.canFind(c)).array); + } + catch(Base64Exception e) + { + throw new Exception("Unable to decode base64 value: " ~ e.msg); + } +} + +@safe unittest +{ + auto test = "The Answer: 42".representation; + char[] buffer; + buffer.length = 256; + string input = Base64.encode(test, buffer).idup; + const value = constructBinary(input); + assert(value == test); + assert(value == [84, 104, 101, 32, 65, 110, 115, 119, 101, 114, 58, 32, 52, 50]); +} + +// Construct a timestamp (SysTime) _node. +SysTime constructTimestamp(const string str) @safe +{ + string value = str; + + auto YMDRegexp = regex("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)"); + auto HMSRegexp = regex("^[Tt \t]+([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(\\.[0-9]*)?"); + auto TZRegexp = regex("^[ \t]*Z|([-+][0-9][0-9]?)(:[0-9][0-9])?"); + + try + { + // First, get year, month and day. + auto matches = match(value, YMDRegexp); + + enforce(!matches.empty, + new Exception("Unable to parse timestamp value: " ~ value)); + + auto captures = matches.front.captures; + const year = to!int(captures[1]); + const month = to!int(captures[2]); + const day = to!int(captures[3]); + + // If available, get hour, minute, second and fraction, if present. + value = matches.front.post; + matches = match(value, HMSRegexp); + if(matches.empty) + { + return SysTime(DateTime(year, month, day), UTC()); + } + + captures = matches.front.captures; + const hour = to!int(captures[1]); + const minute = to!int(captures[2]); + const second = to!int(captures[3]); + const hectonanosecond = cast(int)(to!real("0" ~ captures[4]) * 10_000_000); + + // If available, get timezone. + value = matches.front.post; + matches = match(value, TZRegexp); + if(matches.empty || matches.front.captures[0] == "Z") + { + // No timezone. + return SysTime(DateTime(year, month, day, hour, minute, second), + hectonanosecond.dur!"hnsecs", UTC()); + } + + // We have a timezone, so parse it. + captures = matches.front.captures; + int sign = 1; + int tzHours; + if(!captures[1].empty) + { + if(captures[1][0] == '-') {sign = -1;} + tzHours = to!int(captures[1][1 .. $]); + } + const tzMinutes = (!captures[2].empty) ? to!int(captures[2][1 .. $]) : 0; + const tzOffset = dur!"minutes"(sign * (60 * tzHours + tzMinutes)); + + return SysTime(DateTime(year, month, day, hour, minute, second), + hectonanosecond.dur!"hnsecs", + new immutable SimpleTimeZone(tzOffset)); + } + catch(ConvException e) + { + throw new Exception("Unable to parse timestamp value " ~ value ~ " : " ~ e.msg); + } + catch(DateTimeException e) + { + throw new Exception("Invalid timestamp value " ~ value ~ " : " ~ e.msg); + } + + assert(false, "This code should never be reached"); +} +@safe unittest +{ + string timestamp(string value) + { + return constructTimestamp(value).toISOString(); + } + + string canonical = "2001-12-15T02:59:43.1Z"; + string iso8601 = "2001-12-14t21:59:43.10-05:00"; + string spaceSeparated = "2001-12-14 21:59:43.10 -5"; + string noTZ = "2001-12-15 2:59:43.10"; + string noFraction = "2001-12-15 2:59:43"; + string ymd = "2002-12-14"; + + assert(timestamp(canonical) == "20011215T025943.1Z"); + //avoiding float conversion errors + assert(timestamp(iso8601) == "20011214T215943.0999999-05:00" || + timestamp(iso8601) == "20011214T215943.1-05:00"); + assert(timestamp(spaceSeparated) == "20011214T215943.0999999-05:00" || + timestamp(spaceSeparated) == "20011214T215943.1-05:00"); + assert(timestamp(noTZ) == "20011215T025943.0999999Z" || + timestamp(noTZ) == "20011215T025943.1Z"); + assert(timestamp(noFraction) == "20011215T025943Z"); + assert(timestamp(ymd) == "20021214T000000Z"); +} + +// Construct a string _node. +string constructString(const string str) @safe +{ + return str; +} + +// Convert a sequence of single-element mappings into a sequence of pairs. +Node.Pair[] getPairs(string type, const Node[] nodes) @safe +{ + Node.Pair[] pairs; + pairs.reserve(nodes.length); + foreach(node; nodes) + { + enforce(node.nodeID == NodeID.mapping && node.length == 1, + new Exception("While constructing " ~ type ~ + ", expected a mapping with single element")); + + pairs ~= node.as!(Node.Pair[]); + } + + return pairs; +} + +// Construct an ordered map (ordered sequence of key:value pairs without duplicates) _node. +Node.Pair[] constructOrderedMap(const Node[] nodes) @safe +{ + auto pairs = getPairs("ordered map", nodes); + + //Detect duplicates. + //TODO this should be replaced by something with deterministic memory allocation. + auto keys = redBlackTree!Node(); + foreach(ref pair; pairs) + { + enforce(!(pair.key in keys), + new Exception("Duplicate entry in an ordered map: " + ~ pair.key.debugString())); + keys.insert(pair.key); + } + return pairs; +} +@safe unittest +{ + Node[] alternateTypes(uint length) @safe + { + Node[] pairs; + foreach(long i; 0 .. length) + { + auto pair = (i % 2) ? Node.Pair(i.to!string, i) : Node.Pair(i, i.to!string); + pairs ~= Node([pair]); + } + return pairs; + } + + Node[] sameType(uint length) @safe + { + Node[] pairs; + foreach(long i; 0 .. length) + { + auto pair = Node.Pair(i.to!string, i); + pairs ~= Node([pair]); + } + return pairs; + } + + assertThrown(constructOrderedMap(alternateTypes(8) ~ alternateTypes(2))); + assertNotThrown(constructOrderedMap(alternateTypes(8))); + assertThrown(constructOrderedMap(sameType(64) ~ sameType(16))); + assertThrown(constructOrderedMap(alternateTypes(64) ~ alternateTypes(16))); + assertNotThrown(constructOrderedMap(sameType(64))); + assertNotThrown(constructOrderedMap(alternateTypes(64))); +} + +// Construct a pairs (ordered sequence of key: value pairs allowing duplicates) _node. +Node.Pair[] constructPairs(const Node[] nodes) @safe +{ + return getPairs("pairs", nodes); +} + +// Construct a set _node. +Node[] constructSet(const Node.Pair[] pairs) @safe +{ + // In future, the map here should be replaced with something with deterministic + // memory allocation if possible. + // Detect duplicates. + ubyte[Node] map; + Node[] nodes; + nodes.reserve(pairs.length); + foreach(pair; pairs) + { + enforce((pair.key in map) is null, new Exception("Duplicate entry in a set")); + map[pair.key] = 0; + nodes ~= pair.key; + } + + return nodes; +} +@safe unittest +{ + Node.Pair[] set(uint length) @safe + { + Node.Pair[] pairs; + foreach(long i; 0 .. length) + { + pairs ~= Node.Pair(i.to!string, YAMLNull()); + } + + return pairs; + } + + auto DuplicatesShort = set(8) ~ set(2); + auto noDuplicatesShort = set(8); + auto DuplicatesLong = set(64) ~ set(4); + auto noDuplicatesLong = set(64); + + bool eq(Node.Pair[] a, Node[] b) + { + if(a.length != b.length){return false;} + foreach(i; 0 .. a.length) + { + if(a[i].key != b[i]) + { + return false; + } + } + return true; + } + + auto nodeDuplicatesShort = DuplicatesShort.dup; + auto nodeNoDuplicatesShort = noDuplicatesShort.dup; + auto nodeDuplicatesLong = DuplicatesLong.dup; + auto nodeNoDuplicatesLong = noDuplicatesLong.dup; + + assertThrown(constructSet(nodeDuplicatesShort)); + assertNotThrown(constructSet(nodeNoDuplicatesShort)); + assertThrown(constructSet(nodeDuplicatesLong)); + assertNotThrown(constructSet(nodeNoDuplicatesLong)); +} + +// Construct a sequence (array) _node. +Node[] constructSequence(Node[] nodes) @safe +{ + return nodes; +} + +// Construct an unordered map (unordered set of key:value _pairs without duplicates) _node. +Node.Pair[] constructMap(Node.Pair[] pairs) @safe +{ + //Detect duplicates. + //TODO this should be replaced by something with deterministic memory allocation. + auto keys = redBlackTree!Node(); + foreach(ref pair; pairs) + { + enforce(!(pair.key in keys), + new Exception("Duplicate entry in a map: " ~ pair.key.debugString())); + keys.insert(pair.key); + } + return pairs; +} diff --git a/src/ext_depends/D-YAML/source/dyaml/dumper.d b/src/ext_depends/D-YAML/source/dyaml/dumper.d new file mode 100644 index 0000000..51f232f --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/dumper.d @@ -0,0 +1,287 @@ + +// 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) + +/** + * YAML dumper. + * + * Code based on $(LINK2 http://www.pyyaml.org, PyYAML). + */ +module dyaml.dumper; + +import std.array; +import std.range.primitives; +import std.typecons; + +import dyaml.emitter; +import dyaml.event; +import dyaml.exception; +import dyaml.linebreak; +import dyaml.node; +import dyaml.representer; +import dyaml.resolver; +import dyaml.serializer; +import dyaml.style; +import dyaml.tagdirective; + + +/** + * Dumps YAML documents to files or streams. + * + * User specified Representer and/or Resolver can be used to support new + * tags / data types. + * + * Setters are provided to affect output details (style, etc.). + */ +auto dumper() +{ + auto dumper = Dumper(); + dumper.resolver = Resolver.withDefaultResolvers; + return dumper; +} + +struct Dumper +{ + private: + //Indentation width. + int indent_ = 2; + //Tag directives to use. + TagDirective[] tags_; + public: + //Resolver to resolve tags. + Resolver resolver; + //Write scalars in canonical form? + bool canonical; + //Preferred text width. + uint textWidth = 80; + //Line break to use. Unix by default. + LineBreak lineBreak = LineBreak.unix; + //YAML version string. Default is 1.1. + string YAMLVersion = "1.1"; + //Always explicitly write document start? Default is no explicit start. + bool explicitStart = false; + //Always explicitly write document end? Default is no explicit end. + bool explicitEnd = false; + + //Name of the output file or stream, used in error messages. + string name = "<unknown>"; + + // Default style for scalar nodes. If style is $(D ScalarStyle.invalid), the _style is chosen automatically. + ScalarStyle defaultScalarStyle = ScalarStyle.invalid; + // 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); + + ///Set indentation width. 2 by default. Must not be zero. + @property void indent(uint indent) pure @safe nothrow + in + { + assert(indent != 0, "Can't use zero YAML indent width"); + } + do + { + indent_ = indent; + } + + /** + * Specify tag directives. + * + * A tag directive specifies a shorthand notation for specifying _tags. + * Each tag directive associates a handle with a prefix. This allows for + * compact tag notation. + * + * Each handle specified MUST start and end with a '!' character + * (a single character "!" handle is allowed as well). + * + * Only alphanumeric characters, '-', and '__' may be used in handles. + * + * Each prefix MUST not be empty. + * + * The "!!" handle is used for default YAML _tags with prefix + * "tag:yaml.org,2002:". This can be overridden. + * + * Params: tags = Tag directives (keys are handles, values are prefixes). + */ + @property void tagDirectives(string[string] tags) pure @safe + { + TagDirective[] t; + foreach(handle, prefix; tags) + { + assert(handle.length >= 1 && handle[0] == '!' && handle[$ - 1] == '!', + "A tag handle is empty or does not start and end with a " ~ + "'!' character : " ~ handle); + assert(prefix.length >= 1, "A tag prefix is empty"); + t ~= TagDirective(handle, prefix); + } + tags_ = t; + } + /// + @safe unittest + { + auto dumper = dumper(); + string[string] directives; + directives["!short!"] = "tag:long.org,2011:"; + //This will emit tags starting with "tag:long.org,2011" + //with a "!short!" prefix instead. + dumper.tagDirectives(directives); + dumper.dump(new Appender!string(), Node("foo")); + } + + /** + * Dump one or more YAML _documents to the file/stream. + * + * Note that while you can call dump() multiple times on the same + * dumper, you will end up writing multiple YAML "files" to the same + * file/stream. + * + * Params: documents = Documents to _dump (root nodes of the _documents). + * + * Throws: YAMLException on error (e.g. invalid nodes, + * unable to write to file/stream). + */ + void dump(CharacterType = char, Range)(Range range, Node[] documents ...) + if (isOutputRange!(Range, CharacterType) && + isOutputRange!(Range, char) || isOutputRange!(Range, wchar) || isOutputRange!(Range, dchar)) + { + try + { + auto emitter = new Emitter!(Range, CharacterType)(range, canonical, indent_, textWidth, lineBreak); + auto serializer = Serializer(resolver, explicitStart ? Yes.explicitStart : No.explicitStart, + explicitEnd ? Yes.explicitEnd : No.explicitEnd, YAMLVersion, tags_); + serializer.startStream(emitter); + foreach(ref document; documents) + { + auto data = representData(document, defaultScalarStyle, defaultCollectionStyle); + serializer.serialize(emitter, data); + } + serializer.endStream(emitter); + } + catch(YAMLException e) + { + throw new YAMLException("Unable to dump YAML to stream " + ~ name ~ " : " ~ e.msg, e.file, e.line); + } + } +} +///Write to a file +@safe unittest +{ + auto node = Node([1, 2, 3, 4, 5]); + dumper().dump(new Appender!string(), node); +} +///Write multiple YAML documents to a file +@safe unittest +{ + auto node1 = Node([1, 2, 3, 4, 5]); + auto node2 = Node("This document contains only one string"); + dumper().dump(new Appender!string(), node1, node2); + //Or with an array: + dumper().dump(new Appender!string(), [node1, node2]); +} +///Write to memory +@safe unittest +{ + auto stream = new Appender!string(); + auto node = Node([1, 2, 3, 4, 5]); + dumper().dump(stream, node); +} +///Use a custom resolver to support custom data types and/or implicit tags +@safe unittest +{ + import std.regex : regex; + auto node = Node([1, 2, 3, 4, 5]); + auto dumper = dumper(); + dumper.resolver.addImplicitResolver("!tag", regex("A.*"), "A"); + dumper.dump(new Appender!string(), node); +} +/// Set default scalar style +@safe unittest +{ + auto stream = new Appender!string(); + auto node = Node("Hello world!"); + auto dumper = dumper(); + dumper.defaultScalarStyle = ScalarStyle.singleQuoted; + dumper.dump(stream, node); +} +/// Set default collection style +@safe unittest +{ + auto stream = new Appender!string(); + auto node = Node(["Hello", "world!"]); + auto dumper = dumper(); + dumper.defaultCollectionStyle = CollectionStyle.flow; + dumper.dump(stream, node); +} +// Make sure the styles are actually used +@safe unittest +{ + auto stream = new Appender!string(); + auto node = Node([Node("Hello world!"), Node(["Hello", "world!"])]); + auto dumper = dumper(); + dumper.defaultScalarStyle = ScalarStyle.singleQuoted; + dumper.defaultCollectionStyle = CollectionStyle.flow; + dumper.explicitEnd = false; + dumper.explicitStart = false; + dumper.YAMLVersion = null; + dumper.dump(stream, node); + assert(stream.data == "[!!str 'Hello world!', [!!str 'Hello', !!str 'world!']]\n"); +} +// Explicit document start/end markers +@safe unittest +{ + auto stream = new Appender!string(); + auto node = Node([1, 2, 3, 4, 5]); + auto dumper = dumper(); + dumper.explicitEnd = true; + dumper.explicitStart = true; + dumper.YAMLVersion = null; + dumper.dump(stream, node); + //Skip version string + assert(stream.data[0..3] == "---"); + //account for newline at end + assert(stream.data[$-4..$-1] == "..."); +} +// No explicit document start/end markers +@safe unittest +{ + auto stream = new Appender!string(); + auto node = Node([1, 2, 3, 4, 5]); + auto dumper = dumper(); + dumper.explicitEnd = false; + dumper.explicitStart = false; + dumper.YAMLVersion = null; + dumper.dump(stream, node); + //Skip version string + assert(stream.data[0..3] != "---"); + //account for newline at end + assert(stream.data[$-4..$-1] != "..."); +} +// Windows, macOS line breaks +@safe unittest +{ + auto node = Node(0); + { + auto stream = new Appender!string(); + auto dumper = dumper(); + dumper.explicitEnd = true; + dumper.explicitStart = true; + dumper.YAMLVersion = null; + dumper.lineBreak = LineBreak.windows; + dumper.dump(stream, node); + assert(stream.data == "--- 0\r\n...\r\n"); + } + { + auto stream = new Appender!string(); + auto dumper = dumper(); + dumper.explicitEnd = true; + dumper.explicitStart = true; + dumper.YAMLVersion = null; + dumper.lineBreak = LineBreak.macintosh; + dumper.dump(stream, node); + assert(stream.data == "--- 0\r...\r"); + } +} diff --git a/src/ext_depends/D-YAML/source/dyaml/emitter.d b/src/ext_depends/D-YAML/source/dyaml/emitter.d new file mode 100644 index 0000000..c797eb9 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/emitter.d @@ -0,0 +1,1689 @@ +// 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) + +/** + * YAML emitter. + * Code based on PyYAML: http://www.pyyaml.org + */ +module dyaml.emitter; + + +import std.algorithm; +import std.array; +import std.ascii; +import std.conv; +import std.encoding; +import std.exception; +import std.format; +import std.range; +import std.string; +import std.system; +import std.typecons; +import std.utf; + +import dyaml.encoding; +import dyaml.escapes; +import dyaml.event; +import dyaml.exception; +import dyaml.linebreak; +import dyaml.queue; +import dyaml.style; +import dyaml.tagdirective; + + +package: + +//Stores results of analysis of a scalar, determining e.g. what scalar style to use. +struct ScalarAnalysis +{ + //Scalar itself. + string scalar; + + enum AnalysisFlags + { + empty = 1<<0, + multiline = 1<<1, + allowFlowPlain = 1<<2, + allowBlockPlain = 1<<3, + allowSingleQuoted = 1<<4, + allowDoubleQuoted = 1<<5, + allowBlock = 1<<6, + isNull = 1<<7 + } + + ///Analysis results. + BitFlags!AnalysisFlags flags; +} + +private alias isNewLine = among!('\n', '\u0085', '\u2028', '\u2029'); + +private alias isSpecialChar = among!('#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\\', '\'', '"', '%', '@', '`'); + +private alias isFlowIndicator = among!(',', '?', '[', ']', '{', '}'); + +private alias isSpace = among!('\0', '\n', '\r', '\u0085', '\u2028', '\u2029', ' ', '\t'); + +//Emits YAML events into a file/stream. +struct Emitter(Range, CharType) if (isOutputRange!(Range, CharType)) +{ + private: + ///Default tag handle shortcuts and replacements. + static TagDirective[] defaultTagDirectives_ = + [TagDirective("!", "!"), TagDirective("!!", "tag:yaml.org,2002:")]; + + ///Stream to write to. + Range stream_; + + /// Type used for upcoming emitter steps + alias EmitterFunction = void function(typeof(this)*) @safe; + + ///Stack of states. + Appender!(EmitterFunction[]) states_; + + ///Current state. + EmitterFunction state_; + + ///Event queue. + Queue!Event events_; + ///Event we're currently emitting. + Event event_; + + ///Stack of previous indentation levels. + Appender!(int[]) indents_; + ///Current indentation level. + int indent_ = -1; + + ///Level of nesting in flow context. If 0, we're in block context. + uint flowLevel_ = 0; + + /// Describes context (where we are in the document). + enum Context + { + /// Root node of a document. + root, + /// Sequence. + sequence, + /// Mapping. + mappingNoSimpleKey, + /// Mapping, in a simple key. + mappingSimpleKey, + } + /// Current context. + Context context_; + + ///Characteristics of the last emitted character: + + ///Line. + uint line_ = 0; + ///Column. + uint column_ = 0; + ///Whitespace character? + bool whitespace_ = true; + ///indentation space, '-', '?', or ':'? + bool indentation_ = true; + + ///Does the document require an explicit document indicator? + bool openEnded_; + + ///Formatting details. + + ///Canonical scalar format? + bool canonical_; + ///Best indentation width. + uint bestIndent_ = 2; + ///Best text width. + uint bestWidth_ = 80; + ///Best line break character/s. + LineBreak bestLineBreak_; + + ///Tag directive handle - prefix pairs. + TagDirective[] tagDirectives_; + + ///Anchor/alias to process. + string preparedAnchor_ = null; + ///Tag to process. + string preparedTag_ = null; + + ///Analysis result of the current scalar. + ScalarAnalysis analysis_; + ///Style of the current scalar. + ScalarStyle style_ = ScalarStyle.invalid; + + public: + @disable int opCmp(ref Emitter); + @disable bool opEquals(ref Emitter); + + /** + * Construct an emitter. + * + * Params: stream = Output range to write to. + * canonical = Write scalars in canonical form? + * indent = Indentation width. + * lineBreak = Line break character/s. + */ + this(Range stream, const bool canonical, const int indent, const int width, + const LineBreak lineBreak) @safe + { + states_.reserve(32); + indents_.reserve(32); + stream_ = stream; + canonical_ = canonical; + nextExpected!"expectStreamStart"(); + + if(indent > 1 && indent < 10){bestIndent_ = indent;} + if(width > bestIndent_ * 2) {bestWidth_ = width;} + bestLineBreak_ = lineBreak; + + analysis_.flags.isNull = true; + } + + ///Emit an event. + void emit(Event event) @safe + { + events_.push(event); + while(!needMoreEvents()) + { + event_ = events_.pop(); + callNext(); + event_.destroy(); + } + } + + private: + ///Pop and return the newest state in states_. + EmitterFunction popState() @safe + in(states_.data.length > 0, + "Emitter: Need to pop a state but there are no states left") + { + const result = states_.data[$-1]; + states_.shrinkTo(states_.data.length - 1); + return result; + } + + void pushState(string D)() @safe + { + states_ ~= mixin("function(typeof(this)* self) { self."~D~"(); }"); + } + + ///Pop and return the newest indent in indents_. + int popIndent() @safe + in(indents_.data.length > 0, + "Emitter: Need to pop an indent level but there" ~ + " are no indent levels left") + { + const result = indents_.data[$-1]; + indents_.shrinkTo(indents_.data.length - 1); + return result; + } + + ///Write a string to the file/stream. + void writeString(const scope char[] str) @safe + { + static if(is(CharType == char)) + { + copy(str, stream_); + } + static if(is(CharType == wchar)) + { + const buffer = to!wstring(str); + copy(buffer, stream_); + } + static if(is(CharType == dchar)) + { + const buffer = to!dstring(str); + copy(buffer, stream_); + } + } + + ///In some cases, we wait for a few next events before emitting. + bool needMoreEvents() @safe nothrow + { + if(events_.length == 0){return true;} + + const event = events_.peek(); + if(event.id == EventID.documentStart){return needEvents(1);} + if(event.id == EventID.sequenceStart){return needEvents(2);} + if(event.id == EventID.mappingStart) {return needEvents(3);} + + return false; + } + + ///Determines if we need specified number of more events. + bool needEvents(in uint count) @safe nothrow + { + int level; + + foreach(const event; events_.range) + { + if(event.id.among!(EventID.documentStart, EventID.sequenceStart, EventID.mappingStart)) {++level;} + else if(event.id.among!(EventID.documentEnd, EventID.sequenceEnd, EventID.mappingEnd)) {--level;} + else if(event.id == EventID.streamStart){level = -1;} + + if(level < 0) + { + return false; + } + } + + return events_.length < (count + 1); + } + + ///Increase indentation level. + void increaseIndent(const Flag!"flow" flow = No.flow, const bool indentless = false) @safe + { + indents_ ~= indent_; + if(indent_ == -1) + { + indent_ = flow ? bestIndent_ : 0; + } + else if(!indentless) + { + indent_ += bestIndent_; + } + } + + ///Determines if the type of current event is as specified. Throws if no event. + bool eventTypeIs(in EventID id) const pure @safe + in(!event_.isNull, "Expected an event, but no event is available.") + { + return event_.id == id; + } + + + //States. + + + //Stream handlers. + + ///Handle start of a file/stream. + void expectStreamStart() @safe + in(eventTypeIs(EventID.streamStart), + "Expected streamStart, but got " ~ event_.idString) + { + + writeStreamStart(); + nextExpected!"expectDocumentStart!(Yes.first)"(); + } + + ///Expect nothing, throwing if we still have something. + void expectNothing() @safe + { + assert(0, "Expected nothing, but got " ~ event_.idString); + } + + //Document handlers. + + ///Handle start of a document. + void expectDocumentStart(Flag!"first" first)() @safe + in(eventTypeIs(EventID.documentStart) || eventTypeIs(EventID.streamEnd), + "Expected documentStart or streamEnd, but got " ~ event_.idString) + { + + if(event_.id == EventID.documentStart) + { + const YAMLVersion = event_.value; + auto tagDirectives = event_.tagDirectives; + if(openEnded_ && (YAMLVersion !is null || tagDirectives !is null)) + { + writeIndicator("...", Yes.needWhitespace); + writeIndent(); + } + + if(YAMLVersion !is null) + { + writeVersionDirective(prepareVersion(YAMLVersion)); + } + + if(tagDirectives !is null) + { + tagDirectives_ = tagDirectives; + sort!"icmp(a.handle, b.handle) < 0"(tagDirectives_); + + foreach(ref pair; tagDirectives_) + { + writeTagDirective(prepareTagHandle(pair.handle), + prepareTagPrefix(pair.prefix)); + } + } + + bool eq(ref TagDirective a, ref TagDirective b){return a.handle == b.handle;} + //Add any default tag directives that have not been overriden. + foreach(ref def; defaultTagDirectives_) + { + if(!std.algorithm.canFind!eq(tagDirectives_, def)) + { + tagDirectives_ ~= def; + } + } + + const implicit = first && !event_.explicitDocument && !canonical_ && + YAMLVersion is null && tagDirectives is null && + !checkEmptyDocument(); + if(!implicit) + { + writeIndent(); + writeIndicator("---", Yes.needWhitespace); + if(canonical_){writeIndent();} + } + nextExpected!"expectRootNode"(); + } + else if(event_.id == EventID.streamEnd) + { + if(openEnded_) + { + writeIndicator("...", Yes.needWhitespace); + writeIndent(); + } + writeStreamEnd(); + nextExpected!"expectNothing"(); + } + } + + ///Handle end of a document. + void expectDocumentEnd() @safe + in(eventTypeIs(EventID.documentEnd), + "Expected DocumentEnd, but got " ~ event_.idString) + { + + writeIndent(); + if(event_.explicitDocument) + { + writeIndicator("...", Yes.needWhitespace); + writeIndent(); + } + nextExpected!"expectDocumentStart!(No.first)"(); + } + + ///Handle the root node of a document. + void expectRootNode() @safe + { + pushState!"expectDocumentEnd"(); + expectNode(Context.root); + } + + ///Handle a mapping node. + // + //Params: simpleKey = Are we in a simple key? + void expectMappingNode(const bool simpleKey = false) @safe + { + expectNode(simpleKey ? Context.mappingSimpleKey : Context.mappingNoSimpleKey); + } + + ///Handle a sequence node. + void expectSequenceNode() @safe + { + expectNode(Context.sequence); + } + + ///Handle a new node. Context specifies where in the document we are. + void expectNode(const Context context) @safe + { + context_ = context; + + const flowCollection = event_.collectionStyle == CollectionStyle.flow; + + switch(event_.id) + { + case EventID.alias_: expectAlias(); break; + case EventID.scalar: + processAnchor("&"); + processTag(); + expectScalar(); + break; + case EventID.sequenceStart: + processAnchor("&"); + processTag(); + if(flowLevel_ > 0 || canonical_ || flowCollection || checkEmptySequence()) + { + expectFlowSequence(); + } + else + { + expectBlockSequence(); + } + break; + case EventID.mappingStart: + processAnchor("&"); + processTag(); + if(flowLevel_ > 0 || canonical_ || flowCollection || checkEmptyMapping()) + { + expectFlowMapping(); + } + else + { + expectBlockMapping(); + } + break; + default: + assert(0, "Expected alias_, scalar, sequenceStart or " ~ + "mappingStart, but got: " ~ event_.idString); + } + } + ///Handle an alias. + void expectAlias() @safe + in(event_.anchor != "", "Anchor is not specified for alias") + { + processAnchor("*"); + nextExpected(popState()); + } + + ///Handle a scalar. + void expectScalar() @safe + { + increaseIndent(Yes.flow); + processScalar(); + indent_ = popIndent(); + nextExpected(popState()); + } + + //Flow sequence handlers. + + ///Handle a flow sequence. + void expectFlowSequence() @safe + { + writeIndicator("[", Yes.needWhitespace, Yes.whitespace); + ++flowLevel_; + increaseIndent(Yes.flow); + nextExpected!"expectFlowSequenceItem!(Yes.first)"(); + } + + ///Handle a flow sequence item. + void expectFlowSequenceItem(Flag!"first" first)() @safe + { + if(event_.id == EventID.sequenceEnd) + { + indent_ = popIndent(); + --flowLevel_; + static if(!first) if(canonical_) + { + writeIndicator(",", No.needWhitespace); + writeIndent(); + } + writeIndicator("]", No.needWhitespace); + nextExpected(popState()); + return; + } + static if(!first){writeIndicator(",", No.needWhitespace);} + if(canonical_ || column_ > bestWidth_){writeIndent();} + pushState!"expectFlowSequenceItem!(No.first)"(); + expectSequenceNode(); + } + + //Flow mapping handlers. + + ///Handle a flow mapping. + void expectFlowMapping() @safe + { + writeIndicator("{", Yes.needWhitespace, Yes.whitespace); + ++flowLevel_; + increaseIndent(Yes.flow); + nextExpected!"expectFlowMappingKey!(Yes.first)"(); + } + + ///Handle a key in a flow mapping. + void expectFlowMappingKey(Flag!"first" first)() @safe + { + if(event_.id == EventID.mappingEnd) + { + indent_ = popIndent(); + --flowLevel_; + static if (!first) if(canonical_) + { + writeIndicator(",", No.needWhitespace); + writeIndent(); + } + writeIndicator("}", No.needWhitespace); + nextExpected(popState()); + return; + } + + static if(!first){writeIndicator(",", No.needWhitespace);} + if(canonical_ || column_ > bestWidth_){writeIndent();} + if(!canonical_ && checkSimpleKey()) + { + pushState!"expectFlowMappingSimpleValue"(); + expectMappingNode(true); + return; + } + + writeIndicator("?", Yes.needWhitespace); + pushState!"expectFlowMappingValue"(); + expectMappingNode(); + } + + ///Handle a simple value in a flow mapping. + void expectFlowMappingSimpleValue() @safe + { + writeIndicator(":", No.needWhitespace); + pushState!"expectFlowMappingKey!(No.first)"(); + expectMappingNode(); + } + + ///Handle a complex value in a flow mapping. + void expectFlowMappingValue() @safe + { + if(canonical_ || column_ > bestWidth_){writeIndent();} + writeIndicator(":", Yes.needWhitespace); + pushState!"expectFlowMappingKey!(No.first)"(); + expectMappingNode(); + } + + //Block sequence handlers. + + ///Handle a block sequence. + void expectBlockSequence() @safe + { + const indentless = (context_ == Context.mappingNoSimpleKey || + context_ == Context.mappingSimpleKey) && !indentation_; + increaseIndent(No.flow, indentless); + nextExpected!"expectBlockSequenceItem!(Yes.first)"(); + } + + ///Handle a block sequence item. + void expectBlockSequenceItem(Flag!"first" first)() @safe + { + static if(!first) if(event_.id == EventID.sequenceEnd) + { + indent_ = popIndent(); + nextExpected(popState()); + return; + } + + writeIndent(); + writeIndicator("-", Yes.needWhitespace, No.whitespace, Yes.indentation); + pushState!"expectBlockSequenceItem!(No.first)"(); + expectSequenceNode(); + } + + //Block mapping handlers. + + ///Handle a block mapping. + void expectBlockMapping() @safe + { + increaseIndent(No.flow); + nextExpected!"expectBlockMappingKey!(Yes.first)"(); + } + + ///Handle a key in a block mapping. + void expectBlockMappingKey(Flag!"first" first)() @safe + { + static if(!first) if(event_.id == EventID.mappingEnd) + { + indent_ = popIndent(); + nextExpected(popState()); + return; + } + + writeIndent(); + if(checkSimpleKey()) + { + pushState!"expectBlockMappingSimpleValue"(); + expectMappingNode(true); + return; + } + + writeIndicator("?", Yes.needWhitespace, No.whitespace, Yes.indentation); + pushState!"expectBlockMappingValue"(); + expectMappingNode(); + } + + ///Handle a simple value in a block mapping. + void expectBlockMappingSimpleValue() @safe + { + writeIndicator(":", No.needWhitespace); + pushState!"expectBlockMappingKey!(No.first)"(); + expectMappingNode(); + } + + ///Handle a complex value in a block mapping. + void expectBlockMappingValue() @safe + { + writeIndent(); + writeIndicator(":", Yes.needWhitespace, No.whitespace, Yes.indentation); + pushState!"expectBlockMappingKey!(No.first)"(); + expectMappingNode(); + } + + //Checkers. + + ///Check if an empty sequence is next. + bool checkEmptySequence() const @safe pure nothrow + { + return event_.id == EventID.sequenceStart && events_.length > 0 + && events_.peek().id == EventID.sequenceEnd; + } + + ///Check if an empty mapping is next. + bool checkEmptyMapping() const @safe pure nothrow + { + return event_.id == EventID.mappingStart && events_.length > 0 + && events_.peek().id == EventID.mappingEnd; + } + + ///Check if an empty document is next. + bool checkEmptyDocument() const @safe pure nothrow + { + if(event_.id != EventID.documentStart || events_.length == 0) + { + return false; + } + + const event = events_.peek(); + const emptyScalar = event.id == EventID.scalar && (event.anchor is null) && + (event.tag is null) && event.implicit && event.value == ""; + return emptyScalar; + } + + ///Check if a simple key is next. + bool checkSimpleKey() @safe + { + uint length; + const id = event_.id; + const scalar = id == EventID.scalar; + const collectionStart = id == EventID.mappingStart || + id == EventID.sequenceStart; + + if((id == EventID.alias_ || scalar || collectionStart) + && (event_.anchor !is null)) + { + if(preparedAnchor_ is null) + { + preparedAnchor_ = prepareAnchor(event_.anchor); + } + length += preparedAnchor_.length; + } + + if((scalar || collectionStart) && (event_.tag !is null)) + { + if(preparedTag_ is null){preparedTag_ = prepareTag(event_.tag);} + length += preparedTag_.length; + } + + if(scalar) + { + if(analysis_.flags.isNull){analysis_ = analyzeScalar(event_.value);} + length += analysis_.scalar.length; + } + + if(length >= 128){return false;} + + return id == EventID.alias_ || + (scalar && !analysis_.flags.empty && !analysis_.flags.multiline) || + checkEmptySequence() || + checkEmptyMapping(); + } + + ///Process and write a scalar. + void processScalar() @safe + { + if(analysis_.flags.isNull){analysis_ = analyzeScalar(event_.value);} + if(style_ == ScalarStyle.invalid) + { + style_ = chooseScalarStyle(); + } + + //if(analysis_.flags.multiline && (context_ != Context.mappingSimpleKey) && + // ([ScalarStyle.invalid, ScalarStyle.plain, ScalarStyle.singleQuoted, ScalarStyle.doubleQuoted) + // .canFind(style_)) + //{ + // writeIndent(); + //} + auto writer = ScalarWriter!(Range, CharType)(&this, analysis_.scalar, + context_ != Context.mappingSimpleKey); + with(writer) final switch(style_) + { + case ScalarStyle.invalid: assert(false); + case ScalarStyle.doubleQuoted: writeDoubleQuoted(); break; + case ScalarStyle.singleQuoted: writeSingleQuoted(); break; + case ScalarStyle.folded: writeFolded(); break; + case ScalarStyle.literal: writeLiteral(); break; + case ScalarStyle.plain: writePlain(); break; + } + analysis_.flags.isNull = true; + style_ = ScalarStyle.invalid; + } + + ///Process and write an anchor/alias. + void processAnchor(const string indicator) @safe + { + if(event_.anchor is null) + { + preparedAnchor_ = null; + return; + } + if(preparedAnchor_ is null) + { + preparedAnchor_ = prepareAnchor(event_.anchor); + } + if(preparedAnchor_ !is null && preparedAnchor_ != "") + { + writeIndicator(indicator, Yes.needWhitespace); + writeString(preparedAnchor_); + } + preparedAnchor_ = null; + } + + ///Process and write a tag. + void processTag() @safe + { + string tag = event_.tag; + + if(event_.id == EventID.scalar) + { + if(style_ == ScalarStyle.invalid){style_ = chooseScalarStyle();} + if((!canonical_ || (tag is null)) && + (style_ == ScalarStyle.plain ? event_.implicit : !event_.implicit && (tag is null))) + { + preparedTag_ = null; + return; + } + if(event_.implicit && (tag is null)) + { + tag = "!"; + preparedTag_ = null; + } + } + else if((!canonical_ || (tag is null)) && event_.implicit) + { + preparedTag_ = null; + return; + } + + assert(tag != "", "Tag is not specified"); + if(preparedTag_ is null){preparedTag_ = prepareTag(tag);} + if(preparedTag_ !is null && preparedTag_ != "") + { + writeIndicator(preparedTag_, Yes.needWhitespace); + } + preparedTag_ = null; + } + + ///Determine style to write the current scalar in. + ScalarStyle chooseScalarStyle() @safe + { + if(analysis_.flags.isNull){analysis_ = analyzeScalar(event_.value);} + + const style = event_.scalarStyle; + const invalidOrPlain = style == ScalarStyle.invalid || style == ScalarStyle.plain; + const block = style == ScalarStyle.literal || style == ScalarStyle.folded; + const singleQuoted = style == ScalarStyle.singleQuoted; + const doubleQuoted = style == ScalarStyle.doubleQuoted; + + const allowPlain = flowLevel_ > 0 ? analysis_.flags.allowFlowPlain + : analysis_.flags.allowBlockPlain; + //simple empty or multiline scalars can't be written in plain style + const simpleNonPlain = (context_ == Context.mappingSimpleKey) && + (analysis_.flags.empty || analysis_.flags.multiline); + + if(doubleQuoted || canonical_) + { + return ScalarStyle.doubleQuoted; + } + + if(invalidOrPlain && event_.implicit && !simpleNonPlain && allowPlain) + { + return ScalarStyle.plain; + } + + if(block && flowLevel_ == 0 && context_ != Context.mappingSimpleKey && + analysis_.flags.allowBlock) + { + return style; + } + + if((invalidOrPlain || singleQuoted) && + analysis_.flags.allowSingleQuoted && + !(context_ == Context.mappingSimpleKey && analysis_.flags.multiline)) + { + return ScalarStyle.singleQuoted; + } + + return ScalarStyle.doubleQuoted; + } + + ///Prepare YAML version string for output. + static string prepareVersion(const string YAMLVersion) @safe + in(YAMLVersion.split(".")[0] == "1", + "Unsupported YAML version: " ~ YAMLVersion) + { + return YAMLVersion; + } + + ///Encode an Unicode character for tag directive and write it to writer. + static void encodeChar(Writer)(ref Writer writer, in dchar c) @safe + { + char[4] data; + const bytes = encode(data, c); + //For each byte add string in format %AB , where AB are hex digits of the byte. + foreach(const char b; data[0 .. bytes]) + { + formattedWrite(writer, "%%%02X", cast(ubyte)b); + } + } + + ///Prepare tag directive handle for output. + static string prepareTagHandle(const string handle) @safe + in(handle != "", "Tag handle must not be empty") + in(handle.drop(1).dropBack(1).all!(c => isAlphaNum(c) || c.among!('-', '_')), + "Tag handle contains invalid characters") + { + return handle; + } + + ///Prepare tag directive prefix for output. + static string prepareTagPrefix(const string prefix) @safe + in(prefix != "", "Tag prefix must not be empty") + { + auto appender = appender!string(); + const int offset = prefix[0] == '!'; + size_t start, end; + + foreach(const size_t i, const dchar c; prefix) + { + const size_t idx = i + offset; + if(isAlphaNum(c) || c.among!('-', ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '!', '~', '*', '\\', '\'', '(', ')', '[', ']', '%')) + { + end = idx + 1; + continue; + } + + if(start < idx){appender.put(prefix[start .. idx]);} + start = end = idx + 1; + + encodeChar(appender, c); + } + + end = min(end, prefix.length); + if(start < end){appender.put(prefix[start .. end]);} + return appender.data; + } + + ///Prepare tag for output. + string prepareTag(in string tag) @safe + in(tag != "", "Tag must not be empty") + { + + string tagString = tag; + if(tagString == "!"){return tagString;} + string handle; + string suffix = tagString; + + //Sort lexicographically by prefix. + sort!"icmp(a.prefix, b.prefix) < 0"(tagDirectives_); + foreach(ref pair; tagDirectives_) + { + auto prefix = pair.prefix; + if(tagString.startsWith(prefix) && + (prefix != "!" || prefix.length < tagString.length)) + { + handle = pair.handle; + suffix = tagString[prefix.length .. $]; + } + } + + auto appender = appender!string(); + appender.put(handle !is null && handle != "" ? handle : "!<"); + size_t start, end; + foreach(const dchar c; suffix) + { + if(isAlphaNum(c) || c.among!('-', ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\\', '\'', '(', ')', '[', ']') || + (c == '!' && handle != "!")) + { + ++end; + continue; + } + if(start < end){appender.put(suffix[start .. end]);} + start = end = end + 1; + + encodeChar(appender, c); + } + + if(start < end){appender.put(suffix[start .. end]);} + if(handle is null || handle == ""){appender.put(">");} + + return appender.data; + } + + ///Prepare anchor for output. + static string prepareAnchor(const string anchor) @safe + in(anchor != "", "Anchor must not be empty") + in(anchor.all!(c => isAlphaNum(c) || c.among!('-', '_')), "Anchor contains invalid characters") + { + return anchor; + } + + ///Analyze specifed scalar and return the analysis result. + static ScalarAnalysis analyzeScalar(string scalar) @safe + { + ScalarAnalysis analysis; + analysis.flags.isNull = false; + analysis.scalar = scalar; + + //Empty scalar is a special case. + if(scalar is null || scalar == "") + { + with(ScalarAnalysis.AnalysisFlags) + analysis.flags = + empty | + allowBlockPlain | + allowSingleQuoted | + allowDoubleQuoted; + return analysis; + } + + //Indicators and special characters (All false by default). + bool blockIndicators, flowIndicators, lineBreaks, specialCharacters; + + //Important whitespace combinations (All false by default). + bool leadingSpace, leadingBreak, trailingSpace, trailingBreak, + breakSpace, spaceBreak; + + //Check document indicators. + if(scalar.startsWith("---", "...")) + { + blockIndicators = flowIndicators = true; + } + + //First character or preceded by a whitespace. + bool preceededByWhitespace = true; + + //Last character or followed by a whitespace. + bool followedByWhitespace = scalar.length == 1 || + scalar[1].among!(' ', '\t', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029'); + + //The previous character is a space/break (false by default). + bool previousSpace, previousBreak; + + foreach(const size_t index, const dchar c; scalar) + { + //Check for indicators. + if(index == 0) + { + //Leading indicators are special characters. + if(c.isSpecialChar) + { + flowIndicators = blockIndicators = true; + } + if(':' == c || '?' == c) + { + flowIndicators = true; + if(followedByWhitespace){blockIndicators = true;} + } + if(c == '-' && followedByWhitespace) + { + flowIndicators = blockIndicators = true; + } + } + else + { + //Some indicators cannot appear within a scalar as well. + if(c.isFlowIndicator){flowIndicators = true;} + if(c == ':') + { + flowIndicators = true; + if(followedByWhitespace){blockIndicators = true;} + } + if(c == '#' && preceededByWhitespace) + { + flowIndicators = blockIndicators = true; + } + } + + //Check for line breaks, special, and unicode characters. + if(c.isNewLine){lineBreaks = true;} + if(!(c == '\n' || (c >= '\x20' && c <= '\x7E')) && + !((c == '\u0085' || (c >= '\xA0' && c <= '\uD7FF') || + (c >= '\uE000' && c <= '\uFFFD')) && c != '\uFEFF')) + { + specialCharacters = true; + } + + //Detect important whitespace combinations. + if(c == ' ') + { + if(index == 0){leadingSpace = true;} + if(index == scalar.length - 1){trailingSpace = true;} + if(previousBreak){breakSpace = true;} + previousSpace = true; + previousBreak = false; + } + else if(c.isNewLine) + { + if(index == 0){leadingBreak = true;} + if(index == scalar.length - 1){trailingBreak = true;} + if(previousSpace){spaceBreak = true;} + previousSpace = false; + previousBreak = true; + } + else + { + previousSpace = previousBreak = false; + } + + //Prepare for the next character. + preceededByWhitespace = c.isSpace != 0; + followedByWhitespace = index + 2 >= scalar.length || + scalar[index + 2].isSpace; + } + + with(ScalarAnalysis.AnalysisFlags) + { + //Let's decide what styles are allowed. + analysis.flags |= allowFlowPlain | allowBlockPlain | allowSingleQuoted | + allowDoubleQuoted | allowBlock; + + //Leading and trailing whitespaces are bad for plain scalars. + if(leadingSpace || leadingBreak || trailingSpace || trailingBreak) + { + analysis.flags &= ~(allowFlowPlain | allowBlockPlain); + } + + //We do not permit trailing spaces for block scalars. + if(trailingSpace) + { + analysis.flags &= ~allowBlock; + } + + //Spaces at the beginning of a new line are only acceptable for block + //scalars. + if(breakSpace) + { + analysis.flags &= ~(allowFlowPlain | allowBlockPlain | allowSingleQuoted); + } + + //Spaces followed by breaks, as well as special character are only + //allowed for double quoted scalars. + if(spaceBreak || specialCharacters) + { + analysis.flags &= ~(allowFlowPlain | allowBlockPlain | allowSingleQuoted | allowBlock); + } + + //Although the plain scalar writer supports breaks, we never emit + //multiline plain scalars. + if(lineBreaks) + { + analysis.flags &= ~(allowFlowPlain | allowBlockPlain); + analysis.flags |= multiline; + } + + //Flow indicators are forbidden for flow plain scalars. + if(flowIndicators) + { + analysis.flags &= ~allowFlowPlain; + } + + //Block indicators are forbidden for block plain scalars. + if(blockIndicators) + { + analysis.flags &= ~allowBlockPlain; + } + } + return analysis; + } + + @safe unittest + { + with(analyzeScalar("").flags) + { + // workaround for empty being std.range.primitives.empty here + alias empty = ScalarAnalysis.AnalysisFlags.empty; + assert(empty && allowBlockPlain && allowSingleQuoted && allowDoubleQuoted); + } + with(analyzeScalar("a").flags) + { + assert(allowFlowPlain && allowBlockPlain && allowSingleQuoted && allowDoubleQuoted && allowBlock); + } + with(analyzeScalar(" ").flags) + { + assert(allowSingleQuoted && allowDoubleQuoted); + } + with(analyzeScalar(" a").flags) + { + assert(allowSingleQuoted && allowDoubleQuoted); + } + with(analyzeScalar("a ").flags) + { + assert(allowSingleQuoted && allowDoubleQuoted); + } + with(analyzeScalar("\na").flags) + { + assert(allowSingleQuoted && allowDoubleQuoted); + } + with(analyzeScalar("a\n").flags) + { + assert(allowSingleQuoted && allowDoubleQuoted); + } + with(analyzeScalar("\n").flags) + { + assert(multiline && allowSingleQuoted && allowDoubleQuoted && allowBlock); + } + with(analyzeScalar(" \n").flags) + { + assert(multiline && allowDoubleQuoted); + } + with(analyzeScalar("\n a").flags) + { + assert(multiline && allowDoubleQuoted && allowBlock); + } + } + + //Writers. + + ///Start the YAML stream (write the unicode byte order mark). + void writeStreamStart() @safe + { + //Write BOM (except for UTF-8) + static if(is(CharType == wchar) || is(CharType == dchar)) + { + stream_.put(cast(CharType)'\uFEFF'); + } + } + + ///End the YAML stream. + void writeStreamEnd() @safe {} + + ///Write an indicator (e.g. ":", "[", ">", etc.). + void writeIndicator(const scope char[] indicator, + const Flag!"needWhitespace" needWhitespace, + const Flag!"whitespace" whitespace = No.whitespace, + const Flag!"indentation" indentation = No.indentation) @safe + { + const bool prefixSpace = !whitespace_ && needWhitespace; + whitespace_ = whitespace; + indentation_ = indentation_ && indentation; + openEnded_ = false; + column_ += indicator.length; + if(prefixSpace) + { + ++column_; + writeString(" "); + } + writeString(indicator); + } + + ///Write indentation. + void writeIndent() @safe + { + const indent = indent_ == -1 ? 0 : indent_; + + if(!indentation_ || column_ > indent || (column_ == indent && !whitespace_)) + { + writeLineBreak(); + } + if(column_ < indent) + { + whitespace_ = true; + + //Used to avoid allocation of arbitrary length strings. + static immutable spaces = " "; + size_t numSpaces = indent - column_; + column_ = indent; + while(numSpaces >= spaces.length) + { + writeString(spaces); + numSpaces -= spaces.length; + } + writeString(spaces[0 .. numSpaces]); + } + } + + ///Start new line. + void writeLineBreak(const scope char[] data = null) @safe + { + whitespace_ = indentation_ = true; + ++line_; + column_ = 0; + writeString(data is null ? lineBreak(bestLineBreak_) : data); + } + + ///Write a YAML version directive. + void writeVersionDirective(const string versionText) @safe + { + writeString("%YAML "); + writeString(versionText); + writeLineBreak(); + } + + ///Write a tag directive. + void writeTagDirective(const string handle, const string prefix) @safe + { + writeString("%TAG "); + writeString(handle); + writeString(" "); + writeString(prefix); + writeLineBreak(); + } + void nextExpected(string D)() @safe + { + state_ = mixin("function(typeof(this)* self) { self."~D~"(); }"); + } + void nextExpected(EmitterFunction f) @safe + { + state_ = f; + } + void callNext() @safe + { + state_(&this); + } +} + + +private: + +///RAII struct used to write out scalar values. +struct ScalarWriter(Range, CharType) +{ + invariant() + { + assert(emitter_.bestIndent_ > 0 && emitter_.bestIndent_ < 10, + "Emitter bestIndent must be 1 to 9 for one-character indent hint"); + } + + private: + @disable int opCmp(ref Emitter!(Range, CharType)); + @disable bool opEquals(ref Emitter!(Range, CharType)); + + ///Used as "null" UTF-32 character. + static immutable dcharNone = dchar.max; + + ///Emitter used to emit the scalar. + Emitter!(Range, CharType)* emitter_; + + ///UTF-8 encoded text of the scalar to write. + string text_; + + ///Can we split the scalar into multiple lines? + bool split_; + ///Are we currently going over spaces in the text? + bool spaces_; + ///Are we currently going over line breaks in the text? + bool breaks_; + + ///Start and end byte of the text range we're currently working with. + size_t startByte_, endByte_; + ///End byte of the text range including the currently processed character. + size_t nextEndByte_; + ///Start and end character of the text range we're currently working with. + long startChar_, endChar_; + + public: + ///Construct a ScalarWriter using emitter to output text. + this(Emitter!(Range, CharType)* emitter, string text, const bool split = true) @safe nothrow + { + emitter_ = emitter; + text_ = text; + split_ = split; + } + + ///Write text as single quoted scalar. + void writeSingleQuoted() @safe + { + emitter_.writeIndicator("\'", Yes.needWhitespace); + spaces_ = breaks_ = false; + resetTextPosition(); + + do + { + const dchar c = nextChar(); + if(spaces_) + { + if(c != ' ' && tooWide() && split_ && + startByte_ != 0 && endByte_ != text_.length) + { + writeIndent(Flag!"ResetSpace".no); + updateRangeStart(); + } + else if(c != ' ') + { + writeCurrentRange(Flag!"UpdateColumn".yes); + } + } + else if(breaks_) + { + if(!c.isNewLine) + { + writeStartLineBreak(); + writeLineBreaks(); + emitter_.writeIndent(); + } + } + else if((c == dcharNone || c == '\'' || c == ' ' || c.isNewLine) + && startChar_ < endChar_) + { + writeCurrentRange(Flag!"UpdateColumn".yes); + } + if(c == '\'') + { + emitter_.column_ += 2; + emitter_.writeString("\'\'"); + startByte_ = endByte_ + 1; + startChar_ = endChar_ + 1; + } + updateBreaks(c, Flag!"UpdateSpaces".yes); + }while(endByte_ < text_.length); + + emitter_.writeIndicator("\'", No.needWhitespace); + } + + ///Write text as double quoted scalar. + void writeDoubleQuoted() @safe + { + resetTextPosition(); + emitter_.writeIndicator("\"", Yes.needWhitespace); + do + { + const dchar c = nextChar(); + //handle special characters + if(c == dcharNone || c.among!('\"', '\\', '\u0085', '\u2028', '\u2029', '\uFEFF') || + !((c >= '\x20' && c <= '\x7E') || + ((c >= '\xA0' && c <= '\uD7FF') || (c >= '\uE000' && c <= '\uFFFD')))) + { + if(startChar_ < endChar_) + { + writeCurrentRange(Flag!"UpdateColumn".yes); + } + if(c != dcharNone) + { + auto appender = appender!string(); + if(const dchar es = toEscape(c)) + { + appender.put('\\'); + appender.put(es); + } + else + { + //Write an escaped Unicode character. + const format = c <= 255 ? "\\x%02X": + c <= 65535 ? "\\u%04X": "\\U%08X"; + formattedWrite(appender, format, cast(uint)c); + } + + emitter_.column_ += appender.data.length; + emitter_.writeString(appender.data); + startChar_ = endChar_ + 1; + startByte_ = nextEndByte_; + } + } + if((endByte_ > 0 && endByte_ < text_.length - strideBack(text_, text_.length)) + && (c == ' ' || startChar_ >= endChar_) + && (emitter_.column_ + endChar_ - startChar_ > emitter_.bestWidth_) + && split_) + { + //text_[2:1] is ok in Python but not in D, so we have to use min() + emitter_.writeString(text_[min(startByte_, endByte_) .. endByte_]); + emitter_.writeString("\\"); + emitter_.column_ += startChar_ - endChar_ + 1; + startChar_ = max(startChar_, endChar_); + startByte_ = max(startByte_, endByte_); + + writeIndent(Flag!"ResetSpace".yes); + if(charAtStart() == ' ') + { + emitter_.writeString("\\"); + ++emitter_.column_; + } + } + }while(endByte_ < text_.length); + emitter_.writeIndicator("\"", No.needWhitespace); + } + + ///Write text as folded block scalar. + void writeFolded() @safe + { + initBlock('>'); + bool leadingSpace = true; + spaces_ = false; + breaks_ = true; + resetTextPosition(); + + do + { + const dchar c = nextChar(); + if(breaks_) + { + if(!c.isNewLine) + { + if(!leadingSpace && c != dcharNone && c != ' ') + { + writeStartLineBreak(); + } + leadingSpace = (c == ' '); + writeLineBreaks(); + if(c != dcharNone){emitter_.writeIndent();} + } + } + else if(spaces_) + { + if(c != ' ' && tooWide()) + { + writeIndent(Flag!"ResetSpace".no); + updateRangeStart(); + } + else if(c != ' ') + { + writeCurrentRange(Flag!"UpdateColumn".yes); + } + } + else if(c == dcharNone || c.isNewLine || c == ' ') + { + writeCurrentRange(Flag!"UpdateColumn".yes); + if(c == dcharNone){emitter_.writeLineBreak();} + } + updateBreaks(c, Flag!"UpdateSpaces".yes); + }while(endByte_ < text_.length); + } + + ///Write text as literal block scalar. + void writeLiteral() @safe + { + initBlock('|'); + breaks_ = true; + resetTextPosition(); + + do + { + const dchar c = nextChar(); + if(breaks_) + { + if(!c.isNewLine) + { + writeLineBreaks(); + if(c != dcharNone){emitter_.writeIndent();} + } + } + else if(c == dcharNone || c.isNewLine) + { + writeCurrentRange(Flag!"UpdateColumn".no); + if(c == dcharNone){emitter_.writeLineBreak();} + } + updateBreaks(c, Flag!"UpdateSpaces".no); + }while(endByte_ < text_.length); + } + + ///Write text as plain scalar. + void writePlain() @safe + { + if(emitter_.context_ == Emitter!(Range, CharType).Context.root){emitter_.openEnded_ = true;} + if(text_ == ""){return;} + if(!emitter_.whitespace_) + { + ++emitter_.column_; + emitter_.writeString(" "); + } + emitter_.whitespace_ = emitter_.indentation_ = false; + spaces_ = breaks_ = false; + resetTextPosition(); + + do + { + const dchar c = nextChar(); + if(spaces_) + { + if(c != ' ' && tooWide() && split_) + { + writeIndent(Flag!"ResetSpace".yes); + updateRangeStart(); + } + else if(c != ' ') + { + writeCurrentRange(Flag!"UpdateColumn".yes); + } + } + else if(breaks_) + { + if(!c.isNewLine) + { + writeStartLineBreak(); + writeLineBreaks(); + writeIndent(Flag!"ResetSpace".yes); + } + } + else if(c == dcharNone || c.isNewLine || c == ' ') + { + writeCurrentRange(Flag!"UpdateColumn".yes); + } + updateBreaks(c, Flag!"UpdateSpaces".yes); + }while(endByte_ < text_.length); + } + + private: + ///Get next character and move end of the text range to it. + @property dchar nextChar() pure @safe + { + ++endChar_; + endByte_ = nextEndByte_; + if(endByte_ >= text_.length){return dcharNone;} + const c = text_[nextEndByte_]; + //c is ascii, no need to decode. + if(c < 0x80) + { + ++nextEndByte_; + return c; + } + return decode(text_, nextEndByte_); + } + + ///Get character at start of the text range. + @property dchar charAtStart() const pure @safe + { + size_t idx = startByte_; + return decode(text_, idx); + } + + ///Is the current line too wide? + @property bool tooWide() const pure @safe nothrow + { + return startChar_ + 1 == endChar_ && + emitter_.column_ > emitter_.bestWidth_; + } + + ///Determine hints (indicators) for block scalar. + size_t determineBlockHints(char[] hints, uint bestIndent) const pure @safe + { + size_t hintsIdx; + if(text_.length == 0) + return hintsIdx; + + dchar lastChar(const string str, ref size_t end) + { + size_t idx = end = end - strideBack(str, end); + return decode(text_, idx); + } + + size_t end = text_.length; + const last = lastChar(text_, end); + const secondLast = end > 0 ? lastChar(text_, end) : 0; + + if(text_[0].isNewLine || text_[0] == ' ') + { + hints[hintsIdx++] = cast(char)('0' + bestIndent); + } + if(!last.isNewLine) + { + hints[hintsIdx++] = '-'; + } + else if(std.utf.count(text_) == 1 || secondLast.isNewLine) + { + hints[hintsIdx++] = '+'; + } + return hintsIdx; + } + + ///Initialize for block scalar writing with specified indicator. + void initBlock(const char indicator) @safe + { + char[4] hints; + hints[0] = indicator; + const hintsLength = 1 + determineBlockHints(hints[1 .. $], emitter_.bestIndent_); + emitter_.writeIndicator(hints[0 .. hintsLength], Yes.needWhitespace); + if(hints.length > 0 && hints[$ - 1] == '+') + { + emitter_.openEnded_ = true; + } + emitter_.writeLineBreak(); + } + + ///Write out the current text range. + void writeCurrentRange(const Flag!"UpdateColumn" updateColumn) @safe + { + emitter_.writeString(text_[startByte_ .. endByte_]); + if(updateColumn){emitter_.column_ += endChar_ - startChar_;} + updateRangeStart(); + } + + ///Write line breaks in the text range. + void writeLineBreaks() @safe + { + foreach(const dchar br; text_[startByte_ .. endByte_]) + { + if(br == '\n'){emitter_.writeLineBreak();} + else + { + char[4] brString; + const bytes = encode(brString, br); + emitter_.writeLineBreak(brString[0 .. bytes]); + } + } + updateRangeStart(); + } + + ///Write line break if start of the text range is a newline. + void writeStartLineBreak() @safe + { + if(charAtStart == '\n'){emitter_.writeLineBreak();} + } + + ///Write indentation, optionally resetting whitespace/indentation flags. + void writeIndent(const Flag!"ResetSpace" resetSpace) @safe + { + emitter_.writeIndent(); + if(resetSpace) + { + emitter_.whitespace_ = emitter_.indentation_ = false; + } + } + + ///Move start of text range to its end. + void updateRangeStart() pure @safe nothrow + { + startByte_ = endByte_; + startChar_ = endChar_; + } + + ///Update the line breaks_ flag, optionally updating the spaces_ flag. + void updateBreaks(in dchar c, const Flag!"UpdateSpaces" updateSpaces) pure @safe + { + if(c == dcharNone){return;} + breaks_ = (c.isNewLine != 0); + if(updateSpaces){spaces_ = c == ' ';} + } + + ///Move to the beginning of text. + void resetTextPosition() pure @safe nothrow + { + startByte_ = endByte_ = nextEndByte_ = 0; + startChar_ = endChar_ = -1; + } +} diff --git a/src/ext_depends/D-YAML/source/dyaml/encoding.d b/src/ext_depends/D-YAML/source/dyaml/encoding.d new file mode 100644 index 0000000..50c10b9 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/encoding.d @@ -0,0 +1,11 @@ +// Copyright Ferdinand Majerech 2014. +// 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) + +module dyaml.encoding; + + +import tinyendian; + +alias Encoding = tinyendian.UTFEncoding; diff --git a/src/ext_depends/D-YAML/source/dyaml/escapes.d b/src/ext_depends/D-YAML/source/dyaml/escapes.d new file mode 100644 index 0000000..32080a2 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/escapes.d @@ -0,0 +1,92 @@ + + +// 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) + +module dyaml.escapes; + +package: + +import std.meta : AliasSeq; +alias escapes = AliasSeq!('0', 'a', 'b', 't', '\t', 'n', 'v', 'f', 'r', 'e', ' ', + '\"', '\\', 'N', '_', 'L', 'P'); + +/// YAML hex codes specifying the length of the hex number. +alias escapeHexCodeList = AliasSeq!('x', 'u', 'U'); + +/// Convert a YAML escape to a dchar. +dchar fromEscape(dchar escape) @safe pure nothrow @nogc +{ + switch(escape) + { + case '0': return '\0'; + case 'a': return '\x07'; + case 'b': return '\x08'; + case 't': return '\x09'; + case '\t': return '\x09'; + case 'n': return '\x0A'; + case 'v': return '\x0B'; + case 'f': return '\x0C'; + case 'r': return '\x0D'; + case 'e': return '\x1B'; + case ' ': return '\x20'; + case '\"': return '\"'; + case '\\': return '\\'; + case 'N': return '\x85'; //'\u0085'; + case '_': return '\xA0'; + case 'L': return '\u2028'; + case 'P': return '\u2029'; + default: assert(false, "No such YAML escape"); + } +} + +/** + * Convert a dchar to a YAML escape. + * + * Params: + * value = The possibly escapable character. + * + * Returns: + * If the character passed as parameter can be escaped, returns the matching + * escape, otherwise returns a null character. + */ +dchar toEscape(dchar value) @safe pure nothrow @nogc +{ + switch(value) + { + case '\0': return '0'; + case '\x07': return 'a'; + case '\x08': return 'b'; + case '\x09': return 't'; + case '\x0A': return 'n'; + case '\x0B': return 'v'; + case '\x0C': return 'f'; + case '\x0D': return 'r'; + case '\x1B': return 'e'; + case '\"': return '\"'; + case '\\': return '\\'; + case '\xA0': return '_'; + case '\x85': return 'N'; + case '\u2028': return 'L'; + case '\u2029': return 'P'; + default: return 0; + } +} + +/// Get the length of a hexadecimal number determined by its hex code. +/// +/// Need a function as associative arrays don't work with @nogc. +/// (And this may be even faster with a function.) +uint escapeHexLength(dchar hexCode) @safe pure nothrow @nogc +{ + switch(hexCode) + { + case 'x': return 2; + case 'u': return 4; + case 'U': return 8; + default: assert(false, "No such YAML hex code"); + } +} + diff --git a/src/ext_depends/D-YAML/source/dyaml/event.d b/src/ext_depends/D-YAML/source/dyaml/event.d new file mode 100644 index 0000000..f4a747f --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/event.d @@ -0,0 +1,243 @@ + +// 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) + +/** + * YAML events. + * Code based on PyYAML: http://www.pyyaml.org + */ +module dyaml.event; + +import std.array; +import std.conv; + +import dyaml.exception; +import dyaml.reader; +import dyaml.tagdirective; +import dyaml.style; + + +package: +///Event types. +enum EventID : ubyte +{ + invalid = 0, /// Invalid (uninitialized) event. + streamStart, /// Stream start + streamEnd, /// Stream end + documentStart, /// Document start + documentEnd, /// Document end + alias_, /// Alias + scalar, /// Scalar + sequenceStart, /// Sequence start + sequenceEnd, /// Sequence end + mappingStart, /// Mapping start + mappingEnd /// Mapping end +} + +/** + * YAML event produced by parser. + * + * 48 bytes on 64bit. + */ +struct Event +{ + @disable int opCmp(ref Event); + + ///Value of the event, if any. + string value; + ///Start position of the event in file/stream. + Mark startMark; + ///End position of the event in file/stream. + Mark endMark; + union + { + struct + { + ///Anchor of the event, if any. + string _anchor; + ///Tag of the event, if any. + string _tag; + } + ///Tag directives, if this is a DocumentStart. + //TagDirectives tagDirectives; + TagDirective[] _tagDirectives; + } + ///Event type. + EventID id = EventID.invalid; + ///Style of scalar event, if this is a scalar event. + ScalarStyle scalarStyle = ScalarStyle.invalid; + union + { + ///Should the tag be implicitly resolved? + bool implicit; + /** + * Is this document event explicit? + * + * Used if this is a DocumentStart or DocumentEnd. + */ + bool explicitDocument; + } + ///Collection style, if this is a SequenceStart or MappingStart. + CollectionStyle collectionStyle = CollectionStyle.invalid; + + ///Is this a null (uninitialized) event? + @property bool isNull() const pure @safe nothrow {return id == EventID.invalid;} + + ///Get string representation of the token ID. + @property string idString() const @safe {return to!string(id);} + + auto ref anchor() inout @trusted pure { + assert(id != EventID.documentStart, "DocumentStart events cannot have anchors."); + return _anchor; + } + + auto ref tag() inout @trusted pure { + assert(id != EventID.documentStart, "DocumentStart events cannot have tags."); + return _tag; + } + + auto ref tagDirectives() inout @trusted pure { + assert(id == EventID.documentStart, "Only DocumentStart events have tag directives."); + return _tagDirectives; + } +} + +/** + * Construct a simple event. + * + * Params: start = Start position of the event in the file/stream. + * end = End position of the event in the file/stream. + * anchor = Anchor, if this is an alias event. + */ +Event event(EventID id)(const Mark start, const Mark end, const string anchor = null) + @safe + in(!(id == EventID.alias_ && anchor == ""), "Missing anchor for alias event") +{ + Event result; + result.startMark = start; + result.endMark = end; + result.anchor = anchor; + result.id = id; + return result; +} + +/** + * Construct a collection (mapping or sequence) start event. + * + * Params: start = Start position of the event in the file/stream. + * end = End position of the event in the file/stream. + * anchor = Anchor of the sequence, if any. + * tag = Tag of the sequence, if specified. + * implicit = Should the tag be implicitly resolved? + * style = Style to use when outputting document. + */ +Event collectionStartEvent(EventID id) + (const Mark start, const Mark end, const string anchor, const string tag, + const bool implicit, const CollectionStyle style) pure @safe nothrow +{ + static assert(id == EventID.sequenceStart || id == EventID.sequenceEnd || + id == EventID.mappingStart || id == EventID.mappingEnd); + Event result; + result.startMark = start; + result.endMark = end; + result.anchor = anchor; + result.tag = tag; + result.id = id; + result.implicit = implicit; + result.collectionStyle = style; + return result; +} + +/** + * Construct a stream start event. + * + * Params: start = Start position of the event in the file/stream. + * end = End position of the event in the file/stream. + */ +Event streamStartEvent(const Mark start, const Mark end) + pure @safe nothrow +{ + Event result; + result.startMark = start; + result.endMark = end; + result.id = EventID.streamStart; + return result; +} + +///Aliases for simple events. +alias streamEndEvent = event!(EventID.streamEnd); +alias aliasEvent = event!(EventID.alias_); +alias sequenceEndEvent = event!(EventID.sequenceEnd); +alias mappingEndEvent = event!(EventID.mappingEnd); + +///Aliases for collection start events. +alias sequenceStartEvent = collectionStartEvent!(EventID.sequenceStart); +alias mappingStartEvent = collectionStartEvent!(EventID.mappingStart); + +/** + * Construct a document start event. + * + * Params: start = Start position of the event in the file/stream. + * end = End position of the event in the file/stream. + * explicit = Is this an explicit document start? + * YAMLVersion = YAML version string of the document. + * tagDirectives = Tag directives of the document. + */ +Event documentStartEvent(const Mark start, const Mark end, const bool explicit, string YAMLVersion, + TagDirective[] tagDirectives) pure @safe nothrow +{ + Event result; + result.value = YAMLVersion; + result.startMark = start; + result.endMark = end; + result.id = EventID.documentStart; + result.explicitDocument = explicit; + result.tagDirectives = tagDirectives; + return result; +} + +/** + * Construct a document end event. + * + * Params: start = Start position of the event in the file/stream. + * end = End position of the event in the file/stream. + * explicit = Is this an explicit document end? + */ +Event documentEndEvent(const Mark start, const Mark end, const bool explicit) pure @safe nothrow +{ + Event result; + result.startMark = start; + result.endMark = end; + result.id = EventID.documentEnd; + result.explicitDocument = explicit; + return result; +} + +/// Construct a scalar event. +/// +/// Params: start = Start position of the event in the file/stream. +/// end = End position of the event in the file/stream. +/// anchor = Anchor of the scalar, if any. +/// tag = Tag of the scalar, if specified. +/// implicit = Should the tag be implicitly resolved? +/// value = String value of the scalar. +/// style = Scalar style. +Event scalarEvent(const Mark start, const Mark end, const string anchor, const string tag, + const bool implicit, const string value, + const ScalarStyle style = ScalarStyle.invalid) @safe pure nothrow @nogc +{ + Event result; + result.value = value; + result.startMark = start; + result.endMark = end; + + result.anchor = anchor; + result.tag = tag; + + result.id = EventID.scalar; + result.scalarStyle = style; + result.implicit = implicit; + return result; +} diff --git a/src/ext_depends/D-YAML/source/dyaml/exception.d b/src/ext_depends/D-YAML/source/dyaml/exception.d new file mode 100644 index 0000000..2f13a44 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/exception.d @@ -0,0 +1,159 @@ + +// 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) + +///Exceptions thrown by D:YAML and _exception related code. +module dyaml.exception; + + +import std.algorithm; +import std.array; +import std.string; +import std.conv; + + +/// Base class for all exceptions thrown by D:YAML. +class YAMLException : Exception +{ + /// Construct a YAMLException with specified message and position where it was thrown. + public this(string msg, string file = __FILE__, size_t line = __LINE__) + @safe pure nothrow + { + super(msg, file, line); + } +} + +/// Position in a YAML stream, used for error messages. +struct Mark +{ + package: + /// File name. + string name_; + /// Line number. + ushort line_; + /// Column number. + ushort column_; + + public: + /// Construct a Mark with specified line and column in the file. + this(string name, const uint line, const uint column) @safe pure nothrow @nogc + { + name_ = name; + line_ = cast(ushort)min(ushort.max, line); + // This *will* overflow on extremely wide files but saves CPU time + // (mark ctor takes ~5% of time) + column_ = cast(ushort)column; + } + + /// Get a file name. + @property string name() @safe pure nothrow @nogc const + { + return name_; + } + + /// Get a line number. + @property ushort line() @safe pure nothrow @nogc const + { + return line_; + } + + /// Get a column number. + @property ushort column() @safe pure nothrow @nogc const + { + return column_; + } + + /// Get a string representation of the mark. + string toString() @safe pure nothrow const + { + // Line/column numbers start at zero internally, make them start at 1. + static string clamped(ushort v) @safe pure nothrow + { + return text(v + 1, v == ushort.max ? " or higher" : ""); + } + return "file " ~ name_ ~ ",line " ~ clamped(line_) ~ ",column " ~ clamped(column_); + } +} + +package: +// A struct storing parameters to the MarkedYAMLException constructor. +struct MarkedYAMLExceptionData +{ + // Context of the error. + string context; + // Position of the context in a YAML buffer. + Mark contextMark; + // The error itself. + string problem; + // Position if the error. + Mark problemMark; +} + +// Base class of YAML exceptions with marked positions of the problem. +abstract class MarkedYAMLException : YAMLException +{ + // Construct a MarkedYAMLException with specified context and problem. + this(string context, const Mark contextMark, string problem, const Mark problemMark, + string file = __FILE__, size_t line = __LINE__) @safe pure nothrow + { + const msg = context ~ '\n' ~ + (contextMark != problemMark ? contextMark.toString() ~ '\n' : "") ~ + problem ~ '\n' ~ problemMark.toString() ~ '\n'; + super(msg, file, line); + } + + // Construct a MarkedYAMLException with specified problem. + this(string problem, const Mark problemMark, + string file = __FILE__, size_t line = __LINE__) + @safe pure nothrow + { + super(problem ~ '\n' ~ problemMark.toString(), file, line); + } + + /// Construct a MarkedYAMLException from a struct storing constructor parameters. + this(ref const(MarkedYAMLExceptionData) data) @safe pure nothrow + { + with(data) this(context, contextMark, problem, problemMark); + } +} + +// Constructors of YAML exceptions are mostly the same, so we use a mixin. +// +// See_Also: YAMLException +template ExceptionCtors() +{ + public this(string msg, string file = __FILE__, size_t line = __LINE__) + @safe pure nothrow + { + super(msg, file, line); + } +} + +// Constructors of marked YAML exceptions are mostly the same, so we use a mixin. +// +// See_Also: MarkedYAMLException +template MarkedExceptionCtors() +{ + public: + this(string context, const Mark contextMark, string problem, + const Mark problemMark, string file = __FILE__, size_t line = __LINE__) + @safe pure nothrow + { + super(context, contextMark, problem, problemMark, + file, line); + } + + this(string problem, const Mark problemMark, + string file = __FILE__, size_t line = __LINE__) + @safe pure nothrow + { + super(problem, problemMark, file, line); + } + + this(ref const(MarkedYAMLExceptionData) data) @safe pure nothrow + { + super(data); + } +} diff --git a/src/ext_depends/D-YAML/source/dyaml/linebreak.d b/src/ext_depends/D-YAML/source/dyaml/linebreak.d new file mode 100644 index 0000000..1f0f661 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/linebreak.d @@ -0,0 +1,32 @@ + +// 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) + +module dyaml.linebreak; + + +///Enumerates platform specific line breaks. +enum LineBreak +{ + ///Unix line break ("\n"). + unix, + ///Windows line break ("\r\n"). + windows, + ///Macintosh line break ("\r"). + macintosh +} + +package: + +//Get line break string for specified line break. +string lineBreak(in LineBreak b) pure @safe nothrow +{ + final switch(b) + { + case LineBreak.unix: return "\n"; + case LineBreak.windows: return "\r\n"; + case LineBreak.macintosh: return "\r"; + } +} diff --git a/src/ext_depends/D-YAML/source/dyaml/loader.d b/src/ext_depends/D-YAML/source/dyaml/loader.d new file mode 100644 index 0000000..7e7096c --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/loader.d @@ -0,0 +1,394 @@ + +// 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) + +/// Class used to load YAML documents. +module dyaml.loader; + + +import std.exception; +import std.file; +import std.stdio : File; +import std.string; + +import dyaml.composer; +import dyaml.constructor; +import dyaml.event; +import dyaml.exception; +import dyaml.node; +import dyaml.parser; +import dyaml.reader; +import dyaml.resolver; +import dyaml.scanner; +import dyaml.token; + + +/** Loads YAML documents from files or char[]. + * + * User specified Constructor and/or Resolver can be used to support new + * tags / data types. + */ +struct Loader +{ + private: + // Processes character data to YAML tokens. + Scanner scanner_; + // Processes tokens to YAML events. + Parser parser_; + // Resolves tags (data types). + Resolver resolver_; + // Name of the input file or stream, used in error messages. + string name_ = "<unknown>"; + // Are we done loading? + bool done_; + // Last node read from stream + Node currentNode; + // Has the range interface been initialized yet? + bool rangeInitialized; + + public: + @disable this(); + @disable int opCmp(ref Loader); + @disable bool opEquals(ref Loader); + + /** Construct a Loader to load YAML from a file. + * + * Params: filename = Name of the file to load from. + * file = Already-opened file to load from. + * + * Throws: YAMLException if the file could not be opened or read. + */ + static Loader fromFile(string filename) @trusted + { + try + { + auto loader = Loader(std.file.read(filename), filename); + return loader; + } + catch(FileException e) + { + throw new YAMLException("Unable to open file %s for YAML loading: %s" + .format(filename, e.msg), e.file, e.line); + } + } + /// ditto + static Loader fromFile(File file) @system + { + auto loader = Loader(file.byChunk(4096).join, file.name); + return loader; + } + + /** Construct a Loader to load YAML from a string. + * + * Params: data = String to load YAML from. The char[] version $(B will) + * overwrite its input during parsing as D:YAML reuses memory. + * + * Returns: Loader loading YAML from given string. + * + * Throws: + * + * YAMLException if data could not be read (e.g. a decoding error) + */ + static Loader fromString(char[] data) @safe + { + return Loader(cast(ubyte[])data); + } + /// Ditto + static Loader fromString(string data) @safe + { + return fromString(data.dup); + } + /// Load a char[]. + @safe unittest + { + assert(Loader.fromString("42".dup).load().as!int == 42); + } + /// Load a string. + @safe unittest + { + assert(Loader.fromString("42").load().as!int == 42); + } + + /** Construct a Loader to load YAML from a buffer. + * + * Params: yamlData = Buffer with YAML data to load. This may be e.g. a file + * loaded to memory or a string with YAML data. Note that + * buffer $(B will) be overwritten, as D:YAML minimizes + * memory allocations by reusing the input _buffer. + * $(B Must not be deleted or modified by the user as long + * as nodes loaded by this Loader are in use!) - Nodes may + * refer to data in this buffer. + * + * Note that D:YAML looks for byte-order-marks YAML files encoded in + * UTF-16/UTF-32 (and sometimes UTF-8) use to specify the encoding and + * endianness, so it should be enough to load an entire file to a buffer and + * pass it to D:YAML, regardless of Unicode encoding. + * + * Throws: YAMLException if yamlData contains data illegal in YAML. + */ + static Loader fromBuffer(ubyte[] yamlData) @safe + { + return Loader(yamlData); + } + /// Ditto + static Loader fromBuffer(void[] yamlData) @system + { + return Loader(yamlData); + } + /// Ditto + private this(void[] yamlData, string name = "<unknown>") @system + { + this(cast(ubyte[])yamlData, name); + } + /// Ditto + private this(ubyte[] yamlData, string name = "<unknown>") @safe + { + resolver_ = Resolver.withDefaultResolvers; + name_ = name; + try + { + auto reader_ = new Reader(yamlData, name); + scanner_ = Scanner(reader_); + parser_ = new Parser(scanner_); + } + catch(YAMLException e) + { + throw new YAMLException("Unable to open %s for YAML loading: %s" + .format(name_, e.msg), e.file, e.line); + } + } + + + /// Set stream _name. Used in debugging messages. + void name(string name) pure @safe nothrow @nogc + { + name_ = name; + } + + /// Specify custom Resolver to use. + auto ref resolver() pure @safe nothrow @nogc + { + return resolver_; + } + + /** Load single YAML document. + * + * If none or more than one YAML document is found, this throws a YAMLException. + * + * This can only be called once; this is enforced by contract. + * + * Returns: Root node of the document. + * + * Throws: YAMLException if there wasn't exactly one document + * or on a YAML parsing error. + */ + Node load() @safe + { + enforce!YAMLException(!empty, "Zero documents in stream"); + auto output = front; + popFront(); + enforce!YAMLException(empty, "More than one document in stream"); + return output; + } + + /** Implements the empty range primitive. + * + * If there's no more documents left in the stream, this will be true. + * + * Returns: `true` if no more documents left, `false` otherwise. + */ + bool empty() @safe + { + // currentNode and done_ are both invalid until popFront is called once + if (!rangeInitialized) + { + popFront(); + } + return done_; + } + /** Implements the popFront range primitive. + * + * Reads the next document from the stream, if possible. + */ + void popFront() @safe + { + // 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()) + { + currentNode = composer.getNode(); + } + else + { + done_ = true; + } + } + /** Implements the front range primitive. + * + * Returns: the current document as a Node. + */ + Node front() @safe + { + // currentNode and done_ are both invalid until popFront is called once + if (!rangeInitialized) + { + popFront(); + } + return currentNode; + } + + // Scan all tokens, throwing them away. Used for benchmarking. + void scanBench() @safe + { + try + { + while(!scanner_.empty) + { + scanner_.popFront(); + } + } + catch(YAMLException e) + { + throw new YAMLException("Unable to scan YAML from stream " ~ + name_ ~ " : " ~ e.msg, e.file, e.line); + } + } + + + // Parse and return all events. Used for debugging. + auto parse() @safe + { + return parser_; + } +} +/// Load single YAML document from a file: +@safe unittest +{ + write("example.yaml", "Hello world!"); + auto rootNode = Loader.fromFile("example.yaml").load(); + assert(rootNode == "Hello world!"); +} +/// Load single YAML document from an already-opened file: +@system unittest +{ + // Open a temporary file + auto file = File.tmpfile; + // Write valid YAML + file.write("Hello world!"); + // Return to the beginning + file.seek(0); + // Load document + auto rootNode = Loader.fromFile(file).load(); + assert(rootNode == "Hello world!"); +} +/// Load all YAML documents from a file: +@safe unittest +{ + import std.array : array; + import std.file : write; + write("example.yaml", + "---\n"~ + "Hello world!\n"~ + "...\n"~ + "---\n"~ + "Hello world 2!\n"~ + "...\n" + ); + auto nodes = Loader.fromFile("example.yaml").array; + assert(nodes.length == 2); +} +/// Iterate over YAML documents in a file, lazily loading them: +@safe unittest +{ + import std.file : write; + write("example.yaml", + "---\n"~ + "Hello world!\n"~ + "...\n"~ + "---\n"~ + "Hello world 2!\n"~ + "...\n" + ); + auto loader = Loader.fromFile("example.yaml"); + + foreach(ref node; loader) + { + //Do something + } +} +/// Load YAML from a string: +@safe unittest +{ + string yaml_input = ("red: '#ff0000'\n" ~ + "green: '#00ff00'\n" ~ + "blue: '#0000ff'"); + + auto colors = Loader.fromString(yaml_input).load(); + + foreach(string color, string value; colors) + { + // Do something with the color and its value... + } +} + +/// Load a file into a buffer in memory and then load YAML from that buffer: +@safe unittest +{ + import std.file : read, write; + import std.stdio : writeln; + // Create a yaml document + write("example.yaml", + "---\n"~ + "Hello world!\n"~ + "...\n"~ + "---\n"~ + "Hello world 2!\n"~ + "...\n" + ); + try + { + string buffer = readText("example.yaml"); + auto yamlNode = Loader.fromString(buffer); + + // Read data from yamlNode here... + } + catch(FileException e) + { + writeln("Failed to read file 'example.yaml'"); + } +} +/// Use a custom resolver to support custom data types and/or implicit tags: +@safe unittest +{ + import std.file : write; + // Create a yaml document + write("example.yaml", + "---\n"~ + "Hello world!\n"~ + "...\n" + ); + + auto loader = Loader.fromFile("example.yaml"); + + // Add resolver expressions here... + // loader.resolver.addImplicitResolver(...); + + auto rootNode = loader.load(); +} + +//Issue #258 - https://github.com/dlang-community/D-YAML/issues/258 +@safe unittest +{ + auto yaml = "{\n\"root\": {\n\t\"key\": \"value\"\n }\n}"; + auto doc = Loader.fromString(yaml).load(); + assert(doc.isValid); +} diff --git a/src/ext_depends/D-YAML/source/dyaml/node.d b/src/ext_depends/D-YAML/source/dyaml/node.d new file mode 100644 index 0000000..24a62a4 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/node.d @@ -0,0 +1,2488 @@ + +// 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) + +/// Node of a YAML document. Used to read YAML data once it's loaded, +/// and to prepare data to emit. +module dyaml.node; + + +import std.algorithm; +import std.array; +import std.conv; +import std.datetime; +import std.exception; +import std.math; +import std.meta : AliasSeq; +import std.range; +import std.string; +import std.traits; +import std.typecons; +import std.variant; + +import dyaml.event; +import dyaml.exception; +import dyaml.style; + +/// Exception thrown at node related errors. +class NodeException : YAMLException +{ + package: + // Construct a NodeException. + // + // Params: msg = Error message. + // start = Start position of the node. + this(string msg, Mark start, string file = __FILE__, size_t line = __LINE__) + @safe + { + super(msg ~ "\nNode at: " ~ start.toString(), file, line); + } +} + +// Node kinds. +enum NodeID : ubyte +{ + scalar, + sequence, + mapping, + invalid +} + +/// Null YAML type. Used in nodes with _null values. +struct YAMLNull +{ + /// Used for string conversion. + string toString() const pure @safe nothrow {return "null";} +} + +// Merge YAML type, used to support "tag:yaml.org,2002:merge". +package struct YAMLMerge{} + +// Key-value pair of YAML nodes, used in mappings. +private struct Pair +{ + public: + /// Key node. + Node key; + /// Value node. + Node value; + + /// Construct a Pair from two values. Will be converted to Nodes if needed. + this(K, V)(K key, V value) + { + static if(is(Unqual!K == Node)){this.key = key;} + else {this.key = Node(key);} + static if(is(Unqual!V == Node)){this.value = value;} + else {this.value = Node(value);} + } + + /// Equality test with another Pair. + bool opEquals(const ref Pair rhs) const @safe + { + return key == rhs.key && value == rhs.value; + } + + // Comparison with another Pair. + int opCmp(ref const(Pair) rhs) const @safe + { + const keyCmp = key.opCmp(rhs.key); + return keyCmp != 0 ? keyCmp + : value.opCmp(rhs.value); + } +} + +enum NodeType +{ + null_, + merge, + boolean, + integer, + decimal, + binary, + timestamp, + string, + mapping, + sequence, + invalid +} + +/** YAML node. + * + * This is a pseudo-dynamic type that can store any YAML value, including a + * sequence or mapping of nodes. You can get data from a Node directly or + * iterate over it if it's a collection. + */ +struct Node +{ + public: + alias Pair = .Pair; + + package: + // YAML value type. + alias Value = Algebraic!(YAMLNull, YAMLMerge, bool, long, real, ubyte[], SysTime, string, + Node.Pair[], Node[]); + + // Can Value hold this type naturally? + enum allowed(T) = isIntegral!T || + isFloatingPoint!T || + isSomeString!T || + is(Unqual!T == bool) || + Value.allowed!T; + + // Stored value. + Value value_; + // Start position of the node. + Mark startMark_; + + // Tag of the node. + string tag_; + // Node scalar style. Used to remember style this node was loaded with. + ScalarStyle scalarStyle = ScalarStyle.invalid; + // Node collection style. Used to remember style this node was loaded with. + CollectionStyle collectionStyle = CollectionStyle.invalid; + + public: + /** Construct a Node from a value. + * + * Any type except for Node can be stored in a Node, but default YAML + * types (integers, floats, strings, timestamps, etc.) will be stored + * more efficiently. To create a node representing a null value, + * construct it from YAMLNull. + * + * If value is a node, its value will be copied directly. The tag and + * other information attached to the original node will be discarded. + * + * If value is an array of nodes or pairs, it is stored directly. + * Otherwise, every value in the array is converted to a node, and + * those nodes are stored. + * + * Note that to emit any non-default types you store + * in a node, you need a Representer to represent them in YAML - + * otherwise emitting will fail. + * + * Params: value = Value to store in the node. + * tag = Overrides tag of the node when emitted, regardless + * of tag determined by Representer. Representer uses + * this to determine YAML data type when a D data type + * maps to multiple different YAML data types. Tag must + * be in full form, e.g. "tag:yaml.org,2002:int", not + * a shortcut, like "!!int". + */ + this(T)(T value, const string tag = null) @safe + if (allowed!T || isArray!T || isAssociativeArray!T || is(Unqual!T == Node) || castableToNode!T) + { + tag_ = tag; + + //Unlike with assignment, we're just copying the value. + static if (is(Unqual!T == Node)) + { + setValue(value.value_); + } + else static if(isSomeString!T) + { + setValue(value.to!string); + } + else static if(is(Unqual!T == bool)) + { + setValue(cast(bool)value); + } + else static if(isIntegral!T) + { + setValue(cast(long)value); + } + else static if(isFloatingPoint!T) + { + setValue(cast(real)value); + } + else static if (isArray!T) + { + alias ElementT = Unqual!(ElementType!T); + // Construction from raw node or pair array. + static if(is(ElementT == Node) || is(ElementT == Node.Pair)) + { + setValue(value); + } + // Need to handle byte buffers separately. + else static if(is(ElementT == byte) || is(ElementT == ubyte)) + { + setValue(cast(ubyte[]) value); + } + else + { + Node[] nodes; + foreach(ref v; value) + { + nodes ~= Node(v); + } + setValue(nodes); + } + } + else static if (isAssociativeArray!T) + { + Node.Pair[] pairs; + foreach(k, ref v; value) + { + pairs ~= Pair(k, v); + } + setValue(pairs); + } + // User defined type. + else + { + setValue(value); + } + } + /// Construct a scalar node + @safe unittest + { + // Integer + { + auto node = Node(5); + } + // String + { + auto node = Node("Hello world!"); + } + // Floating point + { + auto node = Node(5.0f); + } + // Boolean + { + auto node = Node(true); + } + // Time + { + auto node = Node(SysTime(DateTime(2005, 6, 15, 20, 0, 0), UTC())); + } + // Integer, dumped as a string + { + auto node = Node(5, "tag:yaml.org,2002:str"); + } + } + /// Construct a sequence node + @safe unittest + { + // Will be emitted as a sequence (default for arrays) + { + auto seq = Node([1, 2, 3, 4, 5]); + } + // Will be emitted as a set (overridden tag) + { + auto set = Node([1, 2, 3, 4, 5], "tag:yaml.org,2002:set"); + } + // Can also store arrays of arrays + { + auto node = Node([[1,2], [3,4]]); + } + } + /// Construct a mapping node + @safe unittest + { + // Will be emitted as an unordered mapping (default for mappings) + auto map = Node([1 : "a", 2 : "b"]); + // Will be emitted as an ordered map (overridden tag) + auto omap = Node([1 : "a", 2 : "b"], "tag:yaml.org,2002:omap"); + // Will be emitted as pairs (overridden tag) + auto pairs = Node([1 : "a", 2 : "b"], "tag:yaml.org,2002:pairs"); + } + @safe unittest + { + { + auto node = Node(42); + assert(node.nodeID == NodeID.scalar); + assert(node.as!int == 42 && node.as!float == 42.0f && node.as!string == "42"); + } + + { + auto node = Node("string"); + assert(node.as!string == "string"); + } + } + @safe unittest + { + with(Node([1, 2, 3])) + { + assert(nodeID == NodeID.sequence); + assert(length == 3); + assert(opIndex(2).as!int == 3); + } + + } + @safe unittest + { + int[string] aa; + aa["1"] = 1; + aa["2"] = 2; + with(Node(aa)) + { + assert(nodeID == NodeID.mapping); + assert(length == 2); + assert(opIndex("2").as!int == 2); + } + } + @safe unittest + { + auto node = Node(Node(4, "tag:yaml.org,2002:str")); + assert(node == 4); + assert(node.tag_ == ""); + } + + /** Construct a node from arrays of _keys and _values. + * + * Constructs a mapping node with key-value pairs from + * _keys and _values, keeping their order. Useful when order + * is important (ordered maps, pairs). + * + * + * keys and values must have equal length. + * + * + * If _keys and/or _values are nodes, they are stored directly/ + * Otherwise they are converted to nodes and then stored. + * + * Params: keys = Keys of the mapping, from first to last pair. + * values = Values of the mapping, from first to last pair. + * tag = Overrides tag of the node when emitted, regardless + * of tag determined by Representer. Representer uses + * this to determine YAML data type when a D data type + * maps to multiple different YAML data types. + * This is used to differentiate between YAML unordered + * mappings ("!!map"), ordered mappings ("!!omap"), and + * pairs ("!!pairs") which are all internally + * represented as an array of node pairs. Tag must be + * in full form, e.g. "tag:yaml.org,2002:omap", not a + * shortcut, like "!!omap". + * + */ + this(K, V)(K[] keys, V[] values, const string tag = null) + if(!(isSomeString!(K[]) || isSomeString!(V[]))) + in(keys.length == values.length, + "Lengths of keys and values arrays to construct " ~ + "a YAML node from don't match") + { + tag_ = tag; + + Node.Pair[] pairs; + foreach(i; 0 .. keys.length){pairs ~= Pair(keys[i], values[i]);} + setValue(pairs); + } + /// + @safe unittest + { + // Will be emitted as an unordered mapping (default for mappings) + auto map = Node([1, 2], ["a", "b"]); + // Will be emitted as an ordered map (overridden tag) + auto omap = Node([1, 2], ["a", "b"], "tag:yaml.org,2002:omap"); + // Will be emitted as pairs (overriden tag) + auto pairs = Node([1, 2], ["a", "b"], "tag:yaml.org,2002:pairs"); + } + @safe unittest + { + with(Node(["1", "2"], [1, 2])) + { + assert(nodeID == NodeID.mapping); + assert(length == 2); + assert(opIndex("2").as!int == 2); + } + + } + + /// Is this node valid (initialized)? + @property bool isValid() const @safe pure nothrow + { + return value_.hasValue; + } + + /// Return tag of the node. + @property string tag() const @safe nothrow + { + return tag_; + } + + /// Return the start position of the node. + @property Mark startMark() const @safe pure nothrow + { + return startMark_; + } + + /** Equality test. + * + * If T is Node, recursively compares all subnodes. + * This might be quite expensive if testing entire documents. + * + * If T is not Node, gets a value of type T from the node and tests + * equality with that. + * + * To test equality with a null YAML value, use YAMLNull. + * + * Params: rhs = Variable to test equality with. + * + * Returns: true if equal, false otherwise. + */ + bool opEquals(const Node rhs) const @safe + { + return opCmp(rhs) == 0; + } + bool opEquals(T)(const auto ref T rhs) const + { + try + { + auto stored = get!(T, No.stringConversion); + // NaNs aren't normally equal to each other, but we'll pretend they are. + static if(isFloatingPoint!T) + { + return rhs == stored || (isNaN(rhs) && isNaN(stored)); + } + else + { + return rhs == stored; + } + } + catch(NodeException e) + { + return false; + } + } + /// + @safe unittest + { + auto node = Node(42); + + assert(node == 42); + assert(node != "42"); + assert(node != "43"); + + auto node2 = Node(YAMLNull()); + assert(node2 == YAMLNull()); + + const node3 = Node(42); + assert(node3 == 42); + } + + /// Shortcut for get(). + alias as = get; + + /** Get the value of the node as specified type. + * + * If the specifed type does not match type in the node, + * conversion is attempted. The stringConversion template + * parameter can be used to disable conversion from non-string + * types to strings. + * + * Numeric values are range checked, throwing if out of range of + * requested type. + * + * Timestamps are stored as std.datetime.SysTime. + * Binary values are decoded and stored as ubyte[]. + * + * To get a null value, use get!YAMLNull . This is to + * prevent getting null values for types such as strings or classes. + * + * $(BR)$(B Mapping default values:) + * + * $(PBR + * The '=' key can be used to denote the default value of a mapping. + * This can be used when a node is scalar in early versions of a program, + * but is replaced by a mapping later. Even if the node is a mapping, the + * get method can be used as if it was a scalar if it has a default value. + * This way, new YAML files where the node is a mapping can still be read + * by old versions of the program, which expect the node to be a scalar. + * ) + * + * Returns: Value of the node as specified type. + * + * Throws: NodeException if unable to convert to specified type, or if + * the value is out of range of requested type. + */ + inout(T) get(T, Flag!"stringConversion" stringConversion = Yes.stringConversion)() inout + if (allowed!(Unqual!T) || hasNodeConstructor!(Unqual!T)) + { + if(isType!(Unqual!T)){return getValue!T;} + + static if(!allowed!(Unqual!T)) + { + static if (hasSimpleNodeConstructor!T) + { + alias params = AliasSeq!(this); + } + else static if (hasExpandedNodeConstructor!T) + { + alias params = AliasSeq!(this, tag_); + } + else + { + static assert(0, "Unknown Node constructor?"); + } + + static if (is(T == class)) + { + return new inout T(params); + } + else static if (is(T == struct)) + { + return T(params); + } + else + { + static assert(0, "Unhandled user type"); + } + } else { + + // If we're getting from a mapping and we're not getting Node.Pair[], + // we're getting the default value. + if(nodeID == NodeID.mapping){return this["="].get!( T, stringConversion);} + + static if(isSomeString!T) + { + static if(!stringConversion) + { + enforce(type == NodeType.string, new NodeException( + "Node stores unexpected type: " ~ text(type) ~ + ". Expected: " ~ typeid(T).toString(), startMark_)); + return to!T(getValue!string); + } + else + { + // Try to convert to string. + try + { + return coerceValue!T(); + } + catch(VariantException e) + { + throw new NodeException("Unable to convert node value to string", startMark_); + } + } + } + else static if(isFloatingPoint!T) + { + final switch (type) + { + case NodeType.integer: + return to!T(getValue!long); + case NodeType.decimal: + return to!T(getValue!real); + case NodeType.binary: + case NodeType.string: + case NodeType.boolean: + case NodeType.null_: + case NodeType.merge: + case NodeType.invalid: + case NodeType.timestamp: + case NodeType.mapping: + case NodeType.sequence: + throw new NodeException("Node stores unexpected type: " ~ text(type) ~ + ". Expected: " ~ typeid(T).toString, startMark_); + } + } + else static if(isIntegral!T) + { + enforce(type == NodeType.integer, new NodeException("Node stores unexpected type: " ~ text(type) ~ + ". Expected: " ~ typeid(T).toString, startMark_)); + immutable temp = getValue!long; + enforce(temp >= T.min && temp <= T.max, + new NodeException("Integer value of type " ~ typeid(T).toString() ~ + " out of range. Value: " ~ to!string(temp), startMark_)); + return temp.to!T; + } + else throw new NodeException("Node stores unexpected type: " ~ text(type) ~ + ". Expected: " ~ typeid(T).toString, startMark_); + } + } + /// Automatic type conversion + @safe unittest + { + auto node = Node(42); + + assert(node.get!int == 42); + assert(node.get!string == "42"); + assert(node.get!double == 42.0); + } + /// Scalar node to struct and vice versa + @safe unittest + { + import dyaml.dumper : dumper; + import dyaml.loader : Loader; + static struct MyStruct + { + int x, y, z; + + this(int x, int y, int z) @safe + { + this.x = x; + this.y = y; + this.z = z; + } + + this(Node node) @safe + { + auto parts = node.as!string().split(":"); + x = parts[0].to!int; + y = parts[1].to!int; + z = parts[2].to!int; + } + + Node opCast(T: Node)() @safe + { + //Using custom scalar format, x:y:z. + auto scalar = format("%s:%s:%s", x, y, z); + //Representing as a scalar, with custom tag to specify this data type. + return Node(scalar, "!mystruct.tag"); + } + } + + auto appender = new Appender!string; + + // Dump struct to yaml document + dumper().dump(appender, Node(MyStruct(1,2,3))); + + // Read yaml document back as a MyStruct + auto loader = Loader.fromString(appender.data); + Node node = loader.load(); + assert(node.as!MyStruct == MyStruct(1,2,3)); + } + /// Sequence node to struct and vice versa + @safe unittest + { + import dyaml.dumper : dumper; + import dyaml.loader : Loader; + static struct MyStruct + { + int x, y, z; + + this(int x, int y, int z) @safe + { + this.x = x; + this.y = y; + this.z = z; + } + + this(Node node) @safe + { + x = node[0].as!int; + y = node[1].as!int; + z = node[2].as!int; + } + + Node opCast(T: Node)() + { + return Node([x, y, z], "!mystruct.tag"); + } + } + + auto appender = new Appender!string; + + // Dump struct to yaml document + dumper().dump(appender, Node(MyStruct(1,2,3))); + + // Read yaml document back as a MyStruct + auto loader = Loader.fromString(appender.data); + Node node = loader.load(); + assert(node.as!MyStruct == MyStruct(1,2,3)); + } + /// Mapping node to struct and vice versa + @safe unittest + { + import dyaml.dumper : dumper; + import dyaml.loader : Loader; + static struct MyStruct + { + int x, y, z; + + Node opCast(T: Node)() + { + auto pairs = [Node.Pair("x", x), + Node.Pair("y", y), + Node.Pair("z", z)]; + return Node(pairs, "!mystruct.tag"); + } + + this(int x, int y, int z) + { + this.x = x; + this.y = y; + this.z = z; + } + + this(Node node) @safe + { + x = node["x"].as!int; + y = node["y"].as!int; + z = node["z"].as!int; + } + } + + auto appender = new Appender!string; + + // Dump struct to yaml document + dumper().dump(appender, Node(MyStruct(1,2,3))); + + // Read yaml document back as a MyStruct + auto loader = Loader.fromString(appender.data); + Node node = loader.load(); + assert(node.as!MyStruct == MyStruct(1,2,3)); + } + /// Classes can be used too + @system unittest { + import dyaml.dumper : dumper; + import dyaml.loader : Loader; + + static class MyClass + { + int x, y, z; + + this(int x, int y, int z) + { + this.x = x; + this.y = y; + this.z = z; + } + + this(Node node) @safe inout + { + auto parts = node.as!string().split(":"); + x = parts[0].to!int; + y = parts[1].to!int; + z = parts[2].to!int; + } + + ///Useful for Node.as!string. + override string toString() + { + return format("MyClass(%s, %s, %s)", x, y, z); + } + + Node opCast(T: Node)() @safe + { + //Using custom scalar format, x:y:z. + auto scalar = format("%s:%s:%s", x, y, z); + //Representing as a scalar, with custom tag to specify this data type. + return Node(scalar, "!myclass.tag"); + } + override bool opEquals(Object o) + { + if (auto other = cast(MyClass)o) + { + return (other.x == x) && (other.y == y) && (other.z == z); + } + return false; + } + } + auto appender = new Appender!string; + + // Dump class to yaml document + dumper().dump(appender, Node(new MyClass(1,2,3))); + + // Read yaml document back as a MyClass + auto loader = Loader.fromString(appender.data); + Node node = loader.load(); + assert(node.as!MyClass == new MyClass(1,2,3)); + } + // Make sure custom tags and styles are kept. + @safe unittest + { + static struct MyStruct + { + Node opCast(T: Node)() + { + auto node = Node("hi", "!mystruct.tag"); + node.setStyle(ScalarStyle.doubleQuoted); + return node; + } + } + + auto node = Node(MyStruct.init); + assert(node.tag == "!mystruct.tag"); + assert(node.scalarStyle == ScalarStyle.doubleQuoted); + } + // ditto, but for collection style + @safe unittest + { + static struct MyStruct + { + Node opCast(T: Node)() + { + auto node = Node(["hi"], "!mystruct.tag"); + node.setStyle(CollectionStyle.flow); + return node; + } + } + + auto node = Node(MyStruct.init); + assert(node.tag == "!mystruct.tag"); + assert(node.collectionStyle == CollectionStyle.flow); + } + @safe unittest + { + assertThrown!NodeException(Node("42").get!int); + assertThrown!NodeException(Node("42").get!double); + assertThrown!NodeException(Node(long.max).get!ushort); + Node(YAMLNull()).get!YAMLNull; + } + @safe unittest + { + const node = Node(42); + assert(node.get!int == 42); + assert(node.get!string == "42"); + assert(node.get!double == 42.0); + + immutable node2 = Node(42); + assert(node2.get!int == 42); + assert(node2.get!(const int) == 42); + assert(node2.get!(immutable int) == 42); + assert(node2.get!string == "42"); + assert(node2.get!(const string) == "42"); + assert(node2.get!(immutable string) == "42"); + assert(node2.get!double == 42.0); + assert(node2.get!(const double) == 42.0); + assert(node2.get!(immutable double) == 42.0); + } + + /** If this is a collection, return its _length. + * + * Otherwise, throw NodeException. + * + * Returns: Number of elements in a sequence or key-value pairs in a mapping. + * + * Throws: NodeException if this is not a sequence nor a mapping. + */ + @property size_t length() const @safe + { + final switch(nodeID) + { + case NodeID.sequence: + return getValue!(Node[]).length; + case NodeID.mapping: + return getValue!(Pair[]).length; + case NodeID.scalar: + case NodeID.invalid: + throw new NodeException("Trying to get length of a " ~ nodeTypeString ~ " node", + startMark_); + } + } + @safe unittest + { + auto node = Node([1,2,3]); + assert(node.length == 3); + const cNode = Node([1,2,3]); + assert(cNode.length == 3); + immutable iNode = Node([1,2,3]); + assert(iNode.length == 3); + } + + /** Get the element at specified index. + * + * If the node is a sequence, index must be integral. + * + * + * If the node is a mapping, return the value corresponding to the first + * key equal to index. containsKey() can be used to determine if a mapping + * has a specific key. + * + * To get element at a null index, use YAMLNull for index. + * + * Params: index = Index to use. + * + * Returns: Value corresponding to the index. + * + * Throws: NodeException if the index could not be found, + * non-integral index is used with a sequence or the node is + * not a collection. + */ + ref inout(Node) opIndex(T)(T index) inout @safe + { + final switch (nodeID) + { + case NodeID.sequence: + checkSequenceIndex(index); + static if(isIntegral!T) + { + return getValue!(Node[])[index]; + } + else + { + assert(false, "Only integers may index sequence nodes"); + } + case NodeID.mapping: + auto idx = findPair(index); + if(idx >= 0) + { + return getValue!(Pair[])[idx].value; + } + + string msg = "Mapping index not found" ~ (isSomeString!T ? ": " ~ to!string(index) : ""); + throw new NodeException(msg, startMark_); + case NodeID.scalar: + case NodeID.invalid: + throw new NodeException("Trying to index a " ~ nodeTypeString ~ " node", startMark_); + } + } + /// + @safe unittest + { + Node narray = Node([11, 12, 13, 14]); + Node nmap = Node(["11", "12", "13", "14"], [11, 12, 13, 14]); + + assert(narray[0].as!int == 11); + assert(null !is collectException(narray[42])); + assert(nmap["11"].as!int == 11); + assert(nmap["14"].as!int == 14); + } + @safe unittest + { + Node narray = Node([11, 12, 13, 14]); + Node nmap = Node(["11", "12", "13", "14"], [11, 12, 13, 14]); + + assert(narray[0].as!int == 11); + assert(null !is collectException(narray[42])); + assert(nmap["11"].as!int == 11); + assert(nmap["14"].as!int == 14); + assert(null !is collectException(nmap["42"])); + + narray.add(YAMLNull()); + nmap.add(YAMLNull(), "Nothing"); + assert(narray[4].as!YAMLNull == YAMLNull()); + assert(nmap[YAMLNull()].as!string == "Nothing"); + + assertThrown!NodeException(nmap[11]); + assertThrown!NodeException(nmap[14]); + } + + /** Determine if a collection contains specified value. + * + * If the node is a sequence, check if it contains the specified value. + * If it's a mapping, check if it has a value that matches specified value. + * + * Params: rhs = Item to look for. Use YAMLNull to check for a null value. + * + * Returns: true if rhs was found, false otherwise. + * + * Throws: NodeException if the node is not a collection. + */ + bool contains(T)(T rhs) const + { + return contains_!(T, No.key, "contains")(rhs); + } + @safe unittest + { + auto mNode = Node(["1", "2", "3"]); + assert(mNode.contains("2")); + const cNode = Node(["1", "2", "3"]); + assert(cNode.contains("2")); + immutable iNode = Node(["1", "2", "3"]); + assert(iNode.contains("2")); + } + + + /** Determine if a mapping contains specified key. + * + * Params: rhs = Key to look for. Use YAMLNull to check for a null key. + * + * Returns: true if rhs was found, false otherwise. + * + * Throws: NodeException if the node is not a mapping. + */ + bool containsKey(T)(T rhs) const + { + return contains_!(T, Yes.key, "containsKey")(rhs); + } + + // Unittest for contains() and containsKey(). + @safe unittest + { + auto seq = Node([1, 2, 3, 4, 5]); + assert(seq.contains(3)); + assert(seq.contains(5)); + assert(!seq.contains("5")); + assert(!seq.contains(6)); + assert(!seq.contains(float.nan)); + assertThrown!NodeException(seq.containsKey(5)); + + auto seq2 = Node(["1", "2"]); + assert(seq2.contains("1")); + assert(!seq2.contains(1)); + + auto map = Node(["1", "2", "3", "4"], [1, 2, 3, 4]); + assert(map.contains(1)); + assert(!map.contains("1")); + assert(!map.contains(5)); + assert(!map.contains(float.nan)); + assert(map.containsKey("1")); + assert(map.containsKey("4")); + assert(!map.containsKey(1)); + assert(!map.containsKey("5")); + + assert(!seq.contains(YAMLNull())); + assert(!map.contains(YAMLNull())); + assert(!map.containsKey(YAMLNull())); + seq.add(YAMLNull()); + map.add("Nothing", YAMLNull()); + assert(seq.contains(YAMLNull())); + assert(map.contains(YAMLNull())); + assert(!map.containsKey(YAMLNull())); + map.add(YAMLNull(), "Nothing"); + assert(map.containsKey(YAMLNull())); + + auto map2 = Node([1, 2, 3, 4], [1, 2, 3, 4]); + assert(!map2.contains("1")); + assert(map2.contains(1)); + assert(!map2.containsKey("1")); + assert(map2.containsKey(1)); + + // scalar + assertThrown!NodeException(Node(1).contains(4)); + assertThrown!NodeException(Node(1).containsKey(4)); + + auto mapNan = Node([1.0, 2, double.nan], [1, double.nan, 5]); + + assert(mapNan.contains(double.nan)); + assert(mapNan.containsKey(double.nan)); + } + + /// Assignment (shallow copy) by value. + void opAssign()(auto ref Node rhs) + { + assumeWontThrow(setValue(rhs.value_)); + startMark_ = rhs.startMark_; + tag_ = rhs.tag_; + scalarStyle = rhs.scalarStyle; + collectionStyle = rhs.collectionStyle; + } + // Unittest for opAssign(). + @safe unittest + { + auto seq = Node([1, 2, 3, 4, 5]); + auto assigned = seq; + assert(seq == assigned, + "Node.opAssign() doesn't produce an equivalent copy"); + } + + /** Set element at specified index in a collection. + * + * This method can only be called on collection nodes. + * + * If the node is a sequence, index must be integral. + * + * If the node is a mapping, sets the _value corresponding to the first + * key matching index (including conversion, so e.g. "42" matches 42). + * + * If the node is a mapping and no key matches index, a new key-value + * pair is added to the mapping. In sequences the index must be in + * range. This ensures behavior siilar to D arrays and associative + * arrays. + * + * To set element at a null index, use YAMLNull for index. + * + * Params: + * value = Value to assign. + * index = Index of the value to set. + * + * Throws: NodeException if the node is not a collection, index is out + * of range or if a non-integral index is used on a sequence node. + */ + void opIndexAssign(K, V)(V value, K index) + { + final switch (nodeID) + { + case NodeID.sequence: + checkSequenceIndex(index); + static if(isIntegral!K || is(Unqual!K == bool)) + { + auto nodes = getValue!(Node[]); + static if(is(Unqual!V == Node)){nodes[index] = value;} + else {nodes[index] = Node(value);} + setValue(nodes); + return; + } + assert(false, "Only integers may index sequence nodes"); + case NodeID.mapping: + const idx = findPair(index); + if(idx < 0){add(index, value);} + else + { + auto pairs = as!(Node.Pair[])(); + static if(is(Unqual!V == Node)){pairs[idx].value = value;} + else {pairs[idx].value = Node(value);} + setValue(pairs); + } + return; + case NodeID.scalar: + case NodeID.invalid: + throw new NodeException("Trying to index a " ~ nodeTypeString ~ " node", startMark_); + } + } + @safe unittest + { + with(Node([1, 2, 3, 4, 3])) + { + opIndexAssign(42, 3); + assert(length == 5); + assert(opIndex(3).as!int == 42); + + opIndexAssign(YAMLNull(), 0); + assert(opIndex(0) == YAMLNull()); + } + with(Node(["1", "2", "3"], [4, 5, 6])) + { + opIndexAssign(42, "3"); + opIndexAssign(123, 456); + assert(length == 4); + assert(opIndex("3").as!int == 42); + assert(opIndex(456).as!int == 123); + + opIndexAssign(43, 3); + //3 and "3" should be different + assert(length == 5); + assert(opIndex("3").as!int == 42); + assert(opIndex(3).as!int == 43); + + opIndexAssign(YAMLNull(), "2"); + assert(opIndex("2") == YAMLNull()); + } + } + + /** Return a range object iterating over a sequence, getting each + * element as T. + * + * If T is Node, simply iterate over the nodes in the sequence. + * Otherwise, convert each node to T during iteration. + * + * Throws: NodeException if the node is not a sequence or an element + * could not be converted to specified type. + */ + template sequence(T = Node) + { + struct Range(N) + { + N subnodes; + size_t position; + + this(N nodes) + { + subnodes = nodes; + position = 0; + } + + /* Input range functionality. */ + bool empty() const @property { return position >= subnodes.length; } + + void popFront() + { + enforce(!empty, "Attempted to popFront an empty sequence"); + position++; + } + + T front() const @property + { + enforce(!empty, "Attempted to take the front of an empty sequence"); + static if (is(Unqual!T == Node)) + return subnodes[position]; + else + return subnodes[position].as!T; + } + + /* Forward range functionality. */ + Range save() { return this; } + + /* Bidirectional range functionality. */ + void popBack() + { + enforce(!empty, "Attempted to popBack an empty sequence"); + subnodes = subnodes[0 .. $ - 1]; + } + + T back() + { + enforce(!empty, "Attempted to take the back of an empty sequence"); + static if (is(Unqual!T == Node)) + return subnodes[$ - 1]; + else + return subnodes[$ - 1].as!T; + } + + /* Random-access range functionality. */ + size_t length() const @property { return subnodes.length; } + T opIndex(size_t index) + { + static if (is(Unqual!T == Node)) + return subnodes[index]; + else + return subnodes[index].as!T; + } + + static assert(isInputRange!Range); + static assert(isForwardRange!Range); + static assert(isBidirectionalRange!Range); + static assert(isRandomAccessRange!Range); + } + auto sequence() + { + enforce(nodeID == NodeID.sequence, + new NodeException("Trying to 'sequence'-iterate over a " ~ nodeTypeString ~ " node", + startMark_)); + return Range!(Node[])(get!(Node[])); + } + auto sequence() const + { + enforce(nodeID == NodeID.sequence, + new NodeException("Trying to 'sequence'-iterate over a " ~ nodeTypeString ~ " node", + startMark_)); + return Range!(const(Node)[])(get!(Node[])); + } + } + @safe unittest + { + Node n1 = Node([1, 2, 3, 4]); + int[int] array; + Node n2 = Node(array); + const n3 = Node([1, 2, 3, 4]); + + auto r = n1.sequence!int.map!(x => x * 10); + assert(r.equal([10, 20, 30, 40])); + + assertThrown(n2.sequence); + + auto r2 = n3.sequence!int.map!(x => x * 10); + assert(r2.equal([10, 20, 30, 40])); + } + + /** Return a range object iterating over mapping's pairs. + * + * Throws: NodeException if the node is not a mapping. + * + */ + template mapping() + { + struct Range(T) + { + T pairs; + size_t position; + + this(T pairs) @safe + { + this.pairs = pairs; + position = 0; + } + + /* Input range functionality. */ + bool empty() @safe { return position >= pairs.length; } + + void popFront() @safe + { + enforce(!empty, "Attempted to popFront an empty mapping"); + position++; + } + + auto front() @safe + { + enforce(!empty, "Attempted to take the front of an empty mapping"); + return pairs[position]; + } + + /* Forward range functionality. */ + Range save() @safe { return this; } + + /* Bidirectional range functionality. */ + void popBack() @safe + { + enforce(!empty, "Attempted to popBack an empty mapping"); + pairs = pairs[0 .. $ - 1]; + } + + auto back() @safe + { + enforce(!empty, "Attempted to take the back of an empty mapping"); + return pairs[$ - 1]; + } + + /* Random-access range functionality. */ + size_t length() const @property @safe { return pairs.length; } + auto opIndex(size_t index) @safe { return pairs[index]; } + + static assert(isInputRange!Range); + static assert(isForwardRange!Range); + static assert(isBidirectionalRange!Range); + static assert(isRandomAccessRange!Range); + } + + auto mapping() + { + enforce(nodeID == NodeID.mapping, + new NodeException("Trying to 'mapping'-iterate over a " + ~ nodeTypeString ~ " node", startMark_)); + return Range!(Node.Pair[])(get!(Node.Pair[])); + } + auto mapping() const + { + enforce(nodeID == NodeID.mapping, + new NodeException("Trying to 'mapping'-iterate over a " + ~ nodeTypeString ~ " node", startMark_)); + return Range!(const(Node.Pair)[])(get!(Node.Pair[])); + } + } + @safe unittest + { + int[int] array; + Node n = Node(array); + n[1] = "foo"; + n[2] = "bar"; + n[3] = "baz"; + + string[int] test; + foreach (pair; n.mapping) + test[pair.key.as!int] = pair.value.as!string; + + assert(test[1] == "foo"); + assert(test[2] == "bar"); + assert(test[3] == "baz"); + + int[int] constArray = [1: 2, 3: 4]; + const x = Node(constArray); + foreach (pair; x.mapping) + assert(pair.value == constArray[pair.key.as!int]); + } + + /** Return a range object iterating over mapping's keys. + * + * If K is Node, simply iterate over the keys in the mapping. + * Otherwise, convert each key to T during iteration. + * + * Throws: NodeException if the nodes is not a mapping or an element + * could not be converted to specified type. + */ + auto mappingKeys(K = Node)() const + { + enforce(nodeID == NodeID.mapping, + new NodeException("Trying to 'mappingKeys'-iterate over a " + ~ nodeTypeString ~ " node", startMark_)); + static if (is(Unqual!K == Node)) + return mapping.map!(pair => pair.key); + else + return mapping.map!(pair => pair.key.as!K); + } + @safe unittest + { + int[int] array; + Node m1 = Node(array); + m1["foo"] = 2; + m1["bar"] = 3; + + assert(m1.mappingKeys.equal(["foo", "bar"]) || m1.mappingKeys.equal(["bar", "foo"])); + + const cm1 = Node(["foo": 2, "bar": 3]); + + assert(cm1.mappingKeys.equal(["foo", "bar"]) || cm1.mappingKeys.equal(["bar", "foo"])); + } + + /** Return a range object iterating over mapping's values. + * + * If V is Node, simply iterate over the values in the mapping. + * Otherwise, convert each key to V during iteration. + * + * Throws: NodeException if the nodes is not a mapping or an element + * could not be converted to specified type. + */ + auto mappingValues(V = Node)() const + { + enforce(nodeID == NodeID.mapping, + new NodeException("Trying to 'mappingValues'-iterate over a " + ~ nodeTypeString ~ " node", startMark_)); + static if (is(Unqual!V == Node)) + return mapping.map!(pair => pair.value); + else + return mapping.map!(pair => pair.value.as!V); + } + @safe unittest + { + int[int] array; + Node m1 = Node(array); + m1["foo"] = 2; + m1["bar"] = 3; + + assert(m1.mappingValues.equal([2, 3]) || m1.mappingValues.equal([3, 2])); + + const cm1 = Node(["foo": 2, "bar": 3]); + + assert(cm1.mappingValues.equal([2, 3]) || cm1.mappingValues.equal([3, 2])); + } + + + /** Foreach over a sequence, getting each element as T. + * + * If T is Node, simply iterate over the nodes in the sequence. + * Otherwise, convert each node to T during iteration. + * + * Throws: NodeException if the node is not a sequence or an + * element could not be converted to specified type. + */ + int opApply(D)(D dg) if (isDelegate!D && (Parameters!D.length == 1)) + { + enforce(nodeID == NodeID.sequence, + new NodeException("Trying to sequence-foreach over a " ~ nodeTypeString ~ " node", + startMark_)); + + int result; + foreach(ref node; get!(Node[])) + { + static if(is(Unqual!(Parameters!D[0]) == Node)) + { + result = dg(node); + } + else + { + Parameters!D[0] temp = node.as!(Parameters!D[0]); + result = dg(temp); + } + if(result){break;} + } + return result; + } + /// ditto + int opApply(D)(D dg) const if (isDelegate!D && (Parameters!D.length == 1)) + { + enforce(nodeID == NodeID.sequence, + new NodeException("Trying to sequence-foreach over a " ~ nodeTypeString ~ " node", + startMark_)); + + int result; + foreach(ref node; get!(Node[])) + { + static if(is(Unqual!(Parameters!D[0]) == Node)) + { + result = dg(node); + } + else + { + Parameters!D[0] temp = node.as!(Parameters!D[0]); + result = dg(temp); + } + if(result){break;} + } + return result; + } + @safe unittest + { + Node n1 = Node(11); + Node n2 = Node(12); + Node n3 = Node(13); + Node n4 = Node(14); + Node narray = Node([n1, n2, n3, n4]); + const cNArray = narray; + + int[] array, array2, array3; + foreach(int value; narray) + { + array ~= value; + } + foreach(Node node; narray) + { + array2 ~= node.as!int; + } + foreach (const Node node; cNArray) + { + array3 ~= node.as!int; + } + assert(array == [11, 12, 13, 14]); + assert(array2 == [11, 12, 13, 14]); + assert(array3 == [11, 12, 13, 14]); + } + @safe unittest + { + string[] testStrs = ["1", "2", "3"]; + auto node1 = Node(testStrs); + int i = 0; + foreach (string elem; node1) + { + assert(elem == testStrs[i]); + i++; + } + const node2 = Node(testStrs); + i = 0; + foreach (string elem; node2) + { + assert(elem == testStrs[i]); + i++; + } + immutable node3 = Node(testStrs); + i = 0; + foreach (string elem; node3) + { + assert(elem == testStrs[i]); + i++; + } + } + @safe unittest + { + auto node = Node(["a":1, "b":2, "c":3]); + const cNode = node; + assertThrown({foreach (Node n; node) {}}()); + assertThrown({foreach (const Node n; cNode) {}}()); + } + + /** Foreach over a mapping, getting each key/value as K/V. + * + * If the K and/or V is Node, simply iterate over the nodes in the mapping. + * Otherwise, convert each key/value to T during iteration. + * + * Throws: NodeException if the node is not a mapping or an + * element could not be converted to specified type. + */ + int opApply(DG)(DG dg) if (isDelegate!DG && (Parameters!DG.length == 2)) + { + alias K = Parameters!DG[0]; + alias V = Parameters!DG[1]; + enforce(nodeID == NodeID.mapping, + new NodeException("Trying to mapping-foreach over a " ~ nodeTypeString ~ " node", + startMark_)); + + int result; + foreach(ref pair; get!(Node.Pair[])) + { + static if(is(Unqual!K == Node) && is(Unqual!V == Node)) + { + result = dg(pair.key, pair.value); + } + else static if(is(Unqual!K == Node)) + { + V tempValue = pair.value.as!V; + result = dg(pair.key, tempValue); + } + else static if(is(Unqual!V == Node)) + { + K tempKey = pair.key.as!K; + result = dg(tempKey, pair.value); + } + else + { + K tempKey = pair.key.as!K; + V tempValue = pair.value.as!V; + result = dg(tempKey, tempValue); + } + + if(result){break;} + } + return result; + } + /// ditto + int opApply(DG)(DG dg) const if (isDelegate!DG && (Parameters!DG.length == 2)) + { + alias K = Parameters!DG[0]; + alias V = Parameters!DG[1]; + enforce(nodeID == NodeID.mapping, + new NodeException("Trying to mapping-foreach over a " ~ nodeTypeString ~ " node", + startMark_)); + + int result; + foreach(ref pair; get!(Node.Pair[])) + { + static if(is(Unqual!K == Node) && is(Unqual!V == Node)) + { + result = dg(pair.key, pair.value); + } + else static if(is(Unqual!K == Node)) + { + V tempValue = pair.value.as!V; + result = dg(pair.key, tempValue); + } + else static if(is(Unqual!V == Node)) + { + K tempKey = pair.key.as!K; + result = dg(tempKey, pair.value); + } + else + { + K tempKey = pair.key.as!K; + V tempValue = pair.value.as!V; + result = dg(tempKey, tempValue); + } + + if(result){break;} + } + return result; + } + @safe unittest + { + Node n1 = Node(cast(long)11); + Node n2 = Node(cast(long)12); + Node n3 = Node(cast(long)13); + Node n4 = Node(cast(long)14); + + Node k1 = Node("11"); + Node k2 = Node("12"); + Node k3 = Node("13"); + Node k4 = Node("14"); + + Node nmap1 = Node([Pair(k1, n1), + Pair(k2, n2), + Pair(k3, n3), + Pair(k4, n4)]); + + int[string] expected = ["11" : 11, + "12" : 12, + "13" : 13, + "14" : 14]; + int[string] array; + foreach(string key, int value; nmap1) + { + array[key] = value; + } + assert(array == expected); + + Node nmap2 = Node([Pair(k1, Node(cast(long)5)), + Pair(k2, Node(true)), + Pair(k3, Node(cast(real)1.0)), + Pair(k4, Node("yarly"))]); + + foreach(string key, Node value; nmap2) + { + switch(key) + { + case "11": assert(value.as!int == 5 ); break; + case "12": assert(value.as!bool == true ); break; + case "13": assert(value.as!float == 1.0 ); break; + case "14": assert(value.as!string == "yarly"); break; + default: assert(false); + } + } + const nmap3 = nmap2; + + foreach(const Node key, const Node value; nmap3) + { + switch(key.as!string) + { + case "11": assert(value.as!int == 5 ); break; + case "12": assert(value.as!bool == true ); break; + case "13": assert(value.as!float == 1.0 ); break; + case "14": assert(value.as!string == "yarly"); break; + default: assert(false); + } + } + } + @safe unittest + { + string[int] testStrs = [0: "1", 1: "2", 2: "3"]; + auto node1 = Node(testStrs); + foreach (const int i, string elem; node1) + { + assert(elem == testStrs[i]); + } + const node2 = Node(testStrs); + foreach (const int i, string elem; node2) + { + assert(elem == testStrs[i]); + } + immutable node3 = Node(testStrs); + foreach (const int i, string elem; node3) + { + assert(elem == testStrs[i]); + } + } + @safe unittest + { + auto node = Node(["a", "b", "c"]); + const cNode = node; + assertThrown({foreach (Node a, Node b; node) {}}()); + assertThrown({foreach (const Node a, const Node b; cNode) {}}()); + } + + /** Add an element to a sequence. + * + * This method can only be called on sequence nodes. + * + * If value is a node, it is copied to the sequence directly. Otherwise + * value is converted to a node and then stored in the sequence. + * + * $(P When emitting, all values in the sequence will be emitted. When + * using the !!set tag, the user needs to ensure that all elements in + * the sequence are unique, otherwise $(B invalid) YAML code will be + * emitted.) + * + * Params: value = Value to _add to the sequence. + */ + void add(T)(T value) + { + if (!isValid) + { + setValue(Node[].init); + } + enforce(nodeID == NodeID.sequence, + new NodeException("Trying to add an element to a " ~ nodeTypeString ~ " node", startMark_)); + + auto nodes = get!(Node[])(); + static if(is(Unqual!T == Node)){nodes ~= value;} + else {nodes ~= Node(value);} + setValue(nodes); + } + @safe unittest + { + with(Node([1, 2, 3, 4])) + { + add(5.0f); + assert(opIndex(4).as!float == 5.0f); + } + with(Node()) + { + add(5.0f); + assert(opIndex(0).as!float == 5.0f); + } + with(Node(5.0f)) + { + assertThrown!NodeException(add(5.0f)); + } + with(Node([5.0f : true])) + { + assertThrown!NodeException(add(5.0f)); + } + } + + /** Add a key-value pair to a mapping. + * + * This method can only be called on mapping nodes. + * + * If key and/or value is a node, it is copied to the mapping directly. + * Otherwise it is converted to a node and then stored in the mapping. + * + * $(P It is possible for the same key to be present more than once in a + * mapping. When emitting, all key-value pairs will be emitted. + * This is useful with the "!!pairs" tag, but will result in + * $(B invalid) YAML with "!!map" and "!!omap" tags.) + * + * Params: key = Key to _add. + * value = Value to _add. + */ + void add(K, V)(K key, V value) + { + if (!isValid) + { + setValue(Node.Pair[].init); + } + enforce(nodeID == NodeID.mapping, + new NodeException("Trying to add a key-value pair to a " ~ + nodeTypeString ~ " node", + startMark_)); + + auto pairs = get!(Node.Pair[])(); + pairs ~= Pair(key, value); + setValue(pairs); + } + @safe unittest + { + with(Node([1, 2], [3, 4])) + { + add(5, "6"); + assert(opIndex(5).as!string == "6"); + } + with(Node()) + { + add(5, "6"); + assert(opIndex(5).as!string == "6"); + } + with(Node(5.0f)) + { + assertThrown!NodeException(add(5, "6")); + } + with(Node([5.0f])) + { + assertThrown!NodeException(add(5, "6")); + } + } + + /** Determine whether a key is in a mapping, and access its value. + * + * This method can only be called on mapping nodes. + * + * Params: key = Key to search for. + * + * Returns: A pointer to the value (as a Node) corresponding to key, + * or null if not found. + * + * Note: Any modification to the node can invalidate the returned + * pointer. + * + * See_Also: contains + */ + inout(Node*) opBinaryRight(string op, K)(K key) inout + if (op == "in") + { + enforce(nodeID == NodeID.mapping, new NodeException("Trying to use 'in' on a " ~ + nodeTypeString ~ " node", startMark_)); + + auto idx = findPair(key); + if(idx < 0) + { + return null; + } + else + { + return &(get!(Node.Pair[])[idx].value); + } + } + @safe unittest + { + auto mapping = Node(["foo", "baz"], ["bar", "qux"]); + assert("bad" !in mapping && ("bad" in mapping) is null); + Node* foo = "foo" in mapping; + assert(foo !is null); + assert(*foo == Node("bar")); + assert(foo.get!string == "bar"); + *foo = Node("newfoo"); + assert(mapping["foo"] == Node("newfoo")); + } + @safe unittest + { + auto mNode = Node(["a": 2]); + assert("a" in mNode); + const cNode = Node(["a": 2]); + assert("a" in cNode); + immutable iNode = Node(["a": 2]); + assert("a" in iNode); + } + + /** Remove first (if any) occurence of a value in a collection. + * + * This method can only be called on collection nodes. + * + * If the node is a sequence, the first node matching value is removed. + * If the node is a mapping, the first key-value pair where _value + * matches specified value is removed. + * + * Params: rhs = Value to _remove. + * + * Throws: NodeException if the node is not a collection. + */ + void remove(T)(T rhs) + { + remove_!(T, No.key, "remove")(rhs); + } + @safe unittest + { + with(Node([1, 2, 3, 4, 3])) + { + remove(3); + assert(length == 4); + assert(opIndex(2).as!int == 4); + assert(opIndex(3).as!int == 3); + + add(YAMLNull()); + assert(length == 5); + remove(YAMLNull()); + assert(length == 4); + } + with(Node(["1", "2", "3"], [4, 5, 6])) + { + remove(4); + assert(length == 2); + add("nullkey", YAMLNull()); + assert(length == 3); + remove(YAMLNull()); + assert(length == 2); + } + } + + /** Remove element at the specified index of a collection. + * + * This method can only be called on collection nodes. + * + * If the node is a sequence, index must be integral. + * + * If the node is a mapping, remove the first key-value pair where + * key matches index. + * + * If the node is a mapping and no key matches index, nothing is removed + * and no exception is thrown. This ensures behavior siilar to D arrays + * and associative arrays. + * + * Params: index = Index to remove at. + * + * Throws: NodeException if the node is not a collection, index is out + * of range or if a non-integral index is used on a sequence node. + */ + void removeAt(T)(T index) + { + remove_!(T, Yes.key, "removeAt")(index); + } + @safe unittest + { + with(Node([1, 2, 3, 4, 3])) + { + removeAt(3); + assertThrown!NodeException(removeAt("3")); + assert(length == 4); + assert(opIndex(3).as!int == 3); + } + with(Node(["1", "2", "3"], [4, 5, 6])) + { + // no integer 2 key, so don't remove anything + removeAt(2); + assert(length == 3); + removeAt("2"); + assert(length == 2); + add(YAMLNull(), "nullval"); + assert(length == 3); + removeAt(YAMLNull()); + assert(length == 2); + } + } + + /// Compare with another _node. + int opCmp(const ref Node rhs) const @safe + { + // Compare tags - if equal or both null, we need to compare further. + const tagCmp = (tag_ is null) ? (rhs.tag_ is null) ? 0 : -1 + : (rhs.tag_ is null) ? 1 : std.algorithm.comparison.cmp(tag_, rhs.tag_); + if(tagCmp != 0){return tagCmp;} + + static int cmp(T1, T2)(T1 a, T2 b) + { + return a > b ? 1 : + a < b ? -1 : + 0; + } + + // Compare validity: if both valid, we have to compare further. + const v1 = isValid; + const v2 = rhs.isValid; + if(!v1){return v2 ? -1 : 0;} + if(!v2){return 1;} + + const typeCmp = cmp(type, rhs.type); + if(typeCmp != 0){return typeCmp;} + + static int compareCollections(T)(const ref Node lhs, const ref Node rhs) + { + const c1 = lhs.getValue!T; + const c2 = rhs.getValue!T; + if(c1 is c2){return 0;} + if(c1.length != c2.length) + { + return cmp(c1.length, c2.length); + } + // Equal lengths, compare items. + foreach(i; 0 .. c1.length) + { + const itemCmp = c1[i].opCmp(c2[i]); + if(itemCmp != 0){return itemCmp;} + } + return 0; + } + + final switch(type) + { + case NodeType.string: + return std.algorithm.cmp(getValue!string, + rhs.getValue!string); + case NodeType.integer: + return cmp(getValue!long, rhs.getValue!long); + case NodeType.boolean: + const b1 = getValue!bool; + const b2 = rhs.getValue!bool; + return b1 ? b2 ? 0 : 1 + : b2 ? -1 : 0; + case NodeType.binary: + const b1 = getValue!(ubyte[]); + const b2 = rhs.getValue!(ubyte[]); + return std.algorithm.cmp(b1, b2); + case NodeType.null_: + return 0; + case NodeType.decimal: + const r1 = getValue!real; + const r2 = rhs.getValue!real; + if(isNaN(r1)) + { + return isNaN(r2) ? 0 : -1; + } + if(isNaN(r2)) + { + return 1; + } + // Fuzzy equality. + if(r1 <= r2 + real.epsilon && r1 >= r2 - real.epsilon) + { + return 0; + } + return cmp(r1, r2); + case NodeType.timestamp: + const t1 = getValue!SysTime; + const t2 = rhs.getValue!SysTime; + return cmp(t1, t2); + case NodeType.mapping: + return compareCollections!(Pair[])(this, rhs); + case NodeType.sequence: + return compareCollections!(Node[])(this, rhs); + case NodeType.merge: + assert(false, "Cannot compare merge nodes"); + case NodeType.invalid: + assert(false, "Cannot compare invalid nodes"); + } + } + + // Ensure opCmp is symmetric for collections + @safe unittest + { + auto node1 = Node( + [ + Node("New York Yankees", "tag:yaml.org,2002:str"), + Node("Atlanta Braves", "tag:yaml.org,2002:str") + ], "tag:yaml.org,2002:seq" + ); + auto node2 = Node( + [ + Node("Detroit Tigers", "tag:yaml.org,2002:str"), + Node("Chicago cubs", "tag:yaml.org,2002:str") + ], "tag:yaml.org,2002:seq" + ); + assert(node1 > node2); + assert(node2 < node1); + } + + // Compute hash of the node. + hash_t toHash() nothrow const @trusted + { + const valueHash = value_.toHash(); + + return tag_ is null ? valueHash : tag_.hashOf(valueHash); + } + @safe unittest + { + assert(Node(42).toHash() != Node(41).toHash()); + assert(Node(42).toHash() != Node(42, "some-tag").toHash()); + } + + /// Get type of the node value. + @property NodeType type() const @safe nothrow + { + if (value_.type is typeid(bool)) + { + return NodeType.boolean; + } + else if (value_.type is typeid(long)) + { + return NodeType.integer; + } + else if (value_.type is typeid(Node[])) + { + return NodeType.sequence; + } + else if (value_.type is typeid(ubyte[])) + { + return NodeType.binary; + } + else if (value_.type is typeid(string)) + { + return NodeType.string; + } + else if (value_.type is typeid(Node.Pair[])) + { + return NodeType.mapping; + } + else if (value_.type is typeid(SysTime)) + { + return NodeType.timestamp; + } + else if (value_.type is typeid(YAMLNull)) + { + return NodeType.null_; + } + else if (value_.type is typeid(YAMLMerge)) + { + return NodeType.merge; + } + else if (value_.type is typeid(real)) + { + return NodeType.decimal; + } + else if (!value_.hasValue) + { + return NodeType.invalid; + } + else assert(0, text(value_.type)); + } + + /// Get the kind of node this is. + @property NodeID nodeID() const @safe nothrow + { + final switch (type) + { + case NodeType.sequence: + return NodeID.sequence; + case NodeType.mapping: + return NodeID.mapping; + case NodeType.boolean: + case NodeType.integer: + case NodeType.binary: + case NodeType.string: + case NodeType.timestamp: + case NodeType.null_: + case NodeType.merge: + case NodeType.decimal: + return NodeID.scalar; + case NodeType.invalid: + return NodeID.invalid; + } + } + package: + + // Get a string representation of the node tree. Used for debugging. + // + // Params: level = Level of the node in the tree. + // + // Returns: String representing the node tree. + @property string debugString(uint level = 0) const @safe + { + string indent; + foreach(i; 0 .. level){indent ~= " ";} + + final switch (nodeID) + { + case NodeID.invalid: + return indent ~ "invalid"; + case NodeID.sequence: + string result = indent ~ "sequence:\n"; + foreach(ref node; get!(Node[])) + { + result ~= node.debugString(level + 1); + } + return result; + case NodeID.mapping: + string result = indent ~ "mapping:\n"; + foreach(ref pair; get!(Node.Pair[])) + { + result ~= indent ~ " pair\n"; + result ~= pair.key.debugString(level + 2); + result ~= pair.value.debugString(level + 2); + } + return result; + case NodeID.scalar: + return indent ~ "scalar(" ~ + (convertsTo!string ? get!string : text(type)) ~ ")\n"; + } + } + + + public: + @property string nodeTypeString() const @safe nothrow + { + final switch (nodeID) + { + case NodeID.mapping: + return "mapping"; + case NodeID.sequence: + return "sequence"; + case NodeID.scalar: + return "scalar"; + case NodeID.invalid: + return "invalid"; + } + } + + // Determine if the value can be converted to specified type. + @property bool convertsTo(T)() const + { + if(isType!T){return true;} + + // Every type allowed in Value should be convertible to string. + static if(isSomeString!T) {return true;} + else static if(isFloatingPoint!T){return type.among!(NodeType.integer, NodeType.decimal);} + else static if(isIntegral!T) {return type == NodeType.integer;} + else static if(is(Unqual!T==bool)){return type == NodeType.boolean;} + else {return false;} + } + /** + * Sets the style of this node when dumped. + * + * Params: style = Any valid style. + */ + void setStyle(CollectionStyle style) @safe + { + enforce(!isValid || (nodeID.among(NodeID.mapping, NodeID.sequence)), new NodeException( + "Cannot set collection style for non-collection nodes", startMark_)); + collectionStyle = style; + } + /// Ditto + void setStyle(ScalarStyle style) @safe + { + enforce(!isValid || (nodeID == NodeID.scalar), new NodeException( + "Cannot set scalar style for non-scalar nodes", startMark_)); + scalarStyle = style; + } + /// + @safe unittest + { + import dyaml.dumper; + auto stream = new Appender!string(); + auto node = Node([1, 2, 3, 4, 5]); + node.setStyle(CollectionStyle.block); + + auto dumper = dumper(); + dumper.dump(stream, node); + } + /// + @safe unittest + { + import dyaml.dumper; + auto stream = new Appender!string(); + auto node = Node(4); + node.setStyle(ScalarStyle.literal); + + auto dumper = dumper(); + dumper.dump(stream, node); + } + @safe unittest + { + assertThrown!NodeException(Node(4).setStyle(CollectionStyle.block)); + assertThrown!NodeException(Node([4]).setStyle(ScalarStyle.literal)); + } + @safe unittest + { + import dyaml.dumper; + { + auto stream = new Appender!string(); + auto node = Node([1, 2, 3, 4, 5]); + node.setStyle(CollectionStyle.block); + auto dumper = dumper(); + dumper.explicitEnd = false; + dumper.explicitStart = false; + dumper.YAMLVersion = null; + dumper.dump(stream, node); + + //Block style should start with a hyphen. + assert(stream.data[0] == '-'); + } + { + auto stream = new Appender!string(); + auto node = Node([1, 2, 3, 4, 5]); + node.setStyle(CollectionStyle.flow); + auto dumper = dumper(); + dumper.explicitEnd = false; + dumper.explicitStart = false; + dumper.YAMLVersion = null; + dumper.dump(stream, node); + + //Flow style should start with a bracket. + assert(stream.data[0] == '['); + } + { + auto stream = new Appender!string(); + auto node = Node(1); + node.setStyle(ScalarStyle.singleQuoted); + auto dumper = dumper(); + dumper.explicitEnd = false; + dumper.explicitStart = false; + dumper.YAMLVersion = null; + dumper.dump(stream, node); + + assert(stream.data == "!!int '1'\n"); + } + { + auto stream = new Appender!string(); + auto node = Node(1); + node.setStyle(ScalarStyle.doubleQuoted); + auto dumper = dumper(); + dumper.explicitEnd = false; + dumper.explicitStart = false; + dumper.YAMLVersion = null; + dumper.dump(stream, node); + + assert(stream.data == "!!int \"1\"\n"); + } + } + + private: + // Determine if the value stored by the node is of specified type. + // + // This only works for default YAML types, not for user defined types. + @property bool isType(T)() const + { + return value_.type is typeid(Unqual!T); + } + + // Implementation of contains() and containsKey(). + bool contains_(T, Flag!"key" key, string func)(T rhs) const + { + final switch (nodeID) + { + case NodeID.mapping: + return findPair!(T, key)(rhs) >= 0; + case NodeID.sequence: + static if(!key) + { + foreach(ref node; getValue!(Node[])) + { + if(node == rhs){return true;} + } + return false; + } + else + { + throw new NodeException("Trying to use " ~ func ~ "() on a " ~ nodeTypeString ~ " node", + startMark_); + } + case NodeID.scalar: + case NodeID.invalid: + throw new NodeException("Trying to use " ~ func ~ "() on a " ~ nodeTypeString ~ " node", + startMark_); + } + + } + + // Implementation of remove() and removeAt() + void remove_(T, Flag!"key" key, string func)(T rhs) + { + static void removeElem(E, I)(ref Node node, I index) + { + auto elems = node.getValue!(E[]); + moveAll(elems[cast(size_t)index + 1 .. $], elems[cast(size_t)index .. $ - 1]); + elems.length = elems.length - 1; + node.setValue(elems); + } + + final switch (nodeID) + { + case NodeID.mapping: + const index = findPair!(T, key)(rhs); + if(index >= 0){removeElem!Pair(this, index);} + break; + case NodeID.sequence: + static long getIndex(ref Node node, ref T rhs) + { + foreach(idx, ref elem; node.get!(Node[])) + { + if(elem.convertsTo!T && elem.as!(T, No.stringConversion) == rhs) + { + return idx; + } + } + return -1; + } + + const index = select!key(rhs, getIndex(this, rhs)); + + // This throws if the index is not integral. + checkSequenceIndex(index); + + static if(isIntegral!(typeof(index))){removeElem!Node(this, index); break; } + else {assert(false, "Non-integral sequence index");} + case NodeID.scalar: + case NodeID.invalid: + throw new NodeException("Trying to " ~ func ~ "() from a " ~ nodeTypeString ~ " node", + startMark_); + } + } + + // Get index of pair with key (or value, if key is false) matching index. + // Cannot be inferred @safe due to https://issues.dlang.org/show_bug.cgi?id=16528 + sizediff_t findPair(T, Flag!"key" key = Yes.key)(const ref T index) const @safe + { + const pairs = getValue!(Pair[])(); + const(Node)* node; + foreach(idx, ref const(Pair) pair; pairs) + { + static if(key){node = &pair.key;} + else {node = &pair.value;} + + + const bool typeMatch = (isFloatingPoint!T && (node.type.among!(NodeType.integer, NodeType.decimal))) || + (isIntegral!T && node.type == NodeType.integer) || + (is(Unqual!T==bool) && node.type == NodeType.boolean) || + (isSomeString!T && node.type == NodeType.string) || + (node.isType!T); + if(typeMatch && *node == index) + { + return idx; + } + } + return -1; + } + + // Check if index is integral and in range. + void checkSequenceIndex(T)(T index) const + { + assert(nodeID == NodeID.sequence, + "checkSequenceIndex() called on a " ~ nodeTypeString ~ " node"); + + static if(!isIntegral!T) + { + throw new NodeException("Indexing a sequence with a non-integral type.", startMark_); + } + else + { + enforce(index >= 0 && index < getValue!(Node[]).length, + new NodeException("Sequence index out of range: " ~ to!string(index), + startMark_)); + } + } + // Safe wrapper for getting a value out of the variant. + inout(T) getValue(T)() @trusted inout + { + return value_.get!T; + } + // Safe wrapper for coercing a value out of the variant. + inout(T) coerceValue(T)() @trusted inout + { + return (cast(Value)value_).coerce!T; + } + // Safe wrapper for setting a value for the variant. + void setValue(T)(T value) @trusted + { + static if (allowed!T) + { + value_ = value; + } + else + { + auto tmpNode = cast(Node)value; + tag_ = tmpNode.tag; + scalarStyle = tmpNode.scalarStyle; + collectionStyle = tmpNode.collectionStyle; + value_ = tmpNode.value_; + } + } +} + +package: +// Merge pairs into an array of pairs based on merge rules in the YAML spec. +// +// Any new pair will only be added if there is not already a pair +// with the same key. +// +// Params: pairs = Appender managing the array of pairs to merge into. +// toMerge = Pairs to merge. +void merge(ref Appender!(Node.Pair[]) pairs, Node.Pair[] toMerge) @safe +{ + bool eq(ref Node.Pair a, ref Node.Pair b){return a.key == b.key;} + + foreach(ref pair; toMerge) if(!canFind!eq(pairs.data, pair)) + { + pairs.put(pair); + } +} + +enum hasNodeConstructor(T) = hasSimpleNodeConstructor!T || hasExpandedNodeConstructor!T; +template hasSimpleNodeConstructor(T) +{ + static if (is(T == struct)) + { + enum hasSimpleNodeConstructor = is(typeof(T(Node.init))); + } + else static if (is(T == class)) + { + enum hasSimpleNodeConstructor = is(typeof(new inout T(Node.init))); + } + else enum hasSimpleNodeConstructor = false; +} +template hasExpandedNodeConstructor(T) +{ + static if (is(T == struct)) + { + enum hasExpandedNodeConstructor = is(typeof(T(Node.init, ""))); + } + else static if (is(T == class)) + { + enum hasExpandedNodeConstructor = is(typeof(new inout T(Node.init, ""))); + } + else enum hasExpandedNodeConstructor = false; +} +enum castableToNode(T) = (is(T == struct) || is(T == class)) && is(typeof(T.opCast!Node()) : Node); diff --git a/src/ext_depends/D-YAML/source/dyaml/package.d b/src/ext_depends/D-YAML/source/dyaml/package.d new file mode 100644 index 0000000..e61b716 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/package.d @@ -0,0 +1,15 @@ +// 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) + +module dyaml; + +public import dyaml.dumper; +public import dyaml.encoding; +public import dyaml.exception; +public import dyaml.linebreak; +public import dyaml.loader; +public import dyaml.resolver; +public import dyaml.style; +public import dyaml.node; diff --git a/src/ext_depends/D-YAML/source/dyaml/parser.d b/src/ext_depends/D-YAML/source/dyaml/parser.d new file mode 100644 index 0000000..7e0b78a --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/parser.d @@ -0,0 +1,958 @@ + +// Copyright Ferdinand Majerech 2011-2014. +// 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) + +/** + * YAML parser. + * Code based on PyYAML: http://www.pyyaml.org + */ +module dyaml.parser; + + +import std.algorithm; +import std.array; +import std.conv; +import std.exception; +import std.typecons; + +import dyaml.event; +import dyaml.exception; +import dyaml.scanner; +import dyaml.style; +import dyaml.token; +import dyaml.tagdirective; + + +package: +/** + * The following YAML grammar is LL(1) and is parsed by a recursive descent + * parser. + * + * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END + * implicit_document ::= block_node DOCUMENT-END* + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + * block_node_or_indentless_sequence ::= + * ALIAS + * | properties (block_content | indentless_block_sequence)? + * | block_content + * | indentless_block_sequence + * block_node ::= ALIAS + * | properties block_content? + * | block_content + * flow_node ::= ALIAS + * | properties flow_content? + * | flow_content + * properties ::= TAG ANCHOR? | ANCHOR TAG? + * block_content ::= block_collection | flow_collection | SCALAR + * flow_content ::= flow_collection | SCALAR + * block_collection ::= block_sequence | block_mapping + * flow_collection ::= flow_sequence | flow_mapping + * block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END + * indentless_sequence ::= (BLOCK-ENTRY block_node?)+ + * block_mapping ::= BLOCK-MAPPING_START + * ((KEY block_node_or_indentless_sequence?)? + * (VALUE block_node_or_indentless_sequence?)?)* + * BLOCK-END + * flow_sequence ::= FLOW-SEQUENCE-START + * (flow_sequence_entry FLOW-ENTRY)* + * flow_sequence_entry? + * FLOW-SEQUENCE-END + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * flow_mapping ::= FLOW-MAPPING-START + * (flow_mapping_entry FLOW-ENTRY)* + * flow_mapping_entry? + * FLOW-MAPPING-END + * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * + * FIRST sets: + * + * stream: { STREAM-START } + * explicit_document: { DIRECTIVE DOCUMENT-START } + * implicit_document: FIRST(block_node) + * block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START } + * flow_node: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START } + * block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR } + * flow_content: { FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR } + * block_collection: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START } + * flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START } + * block_sequence: { BLOCK-SEQUENCE-START } + * block_mapping: { BLOCK-MAPPING-START } + * block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START BLOCK-ENTRY } + * indentless_sequence: { ENTRY } + * flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START } + * flow_sequence: { FLOW-SEQUENCE-START } + * flow_mapping: { FLOW-MAPPING-START } + * flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY } + * flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY } + */ + + +/** + * Marked exception thrown at parser errors. + * + * See_Also: MarkedYAMLException + */ +class ParserException : MarkedYAMLException +{ + mixin MarkedExceptionCtors; +} + +/// Generates events from tokens provided by a Scanner. +/// +/// While Parser receives tokens with non-const character slices, the events it +/// produces are immutable strings, which are usually the same slices, cast to string. +/// Parser is the last layer of D:YAML that may possibly do any modifications to these +/// slices. +final class Parser +{ + private: + ///Default tag handle shortcuts and replacements. + static TagDirective[] defaultTagDirectives_ = + [TagDirective("!", "!"), TagDirective("!!", "tag:yaml.org,2002:")]; + + ///Scanner providing YAML tokens. + Scanner scanner_; + + ///Event produced by the most recent state. + Event currentEvent_; + + ///YAML version string. + string YAMLVersion_ = null; + ///Tag handle shortcuts and replacements. + TagDirective[] tagDirectives_; + + ///Stack of states. + Appender!(Event delegate() @safe[]) states_; + ///Stack of marks used to keep track of extents of e.g. YAML collections. + Appender!(Mark[]) marks_; + + ///Current state. + Event delegate() @safe state_; + + public: + ///Construct a Parser using specified Scanner. + this(Scanner scanner) @safe + { + state_ = &parseStreamStart; + scanner_ = scanner; + states_.reserve(32); + marks_.reserve(32); + } + + /** + * Check if any events are left. May have side effects in some cases. + */ + bool empty() @safe + { + ensureState(); + return currentEvent_.isNull; + } + + /** + * Return the current event. + * + * Must not be called if there are no events left. + */ + Event front() @safe + { + ensureState(); + assert(!currentEvent_.isNull, "No event left to peek"); + return currentEvent_; + } + + /** + * Skip to the next event. + * + * Must not be called if there are no events left. + */ + void popFront() @safe + { + currentEvent_.id = EventID.invalid; + ensureState(); + } + + private: + /// If current event is invalid, load the next valid one if possible. + void ensureState() @safe + { + if(currentEvent_.isNull && state_ !is null) + { + currentEvent_ = state_(); + } + } + ///Pop and return the newest state in states_. + Event delegate() @safe popState() @safe + { + enforce(states_.data.length > 0, + new YAMLException("Parser: Need to pop state but no states left to pop")); + const result = states_.data.back; + states_.shrinkTo(states_.data.length - 1); + return result; + } + + ///Pop and return the newest mark in marks_. + Mark popMark() @safe + { + enforce(marks_.data.length > 0, + new YAMLException("Parser: Need to pop mark but no marks left to pop")); + const result = marks_.data.back; + marks_.shrinkTo(marks_.data.length - 1); + return result; + } + + /// Push a state on the stack + void pushState(Event delegate() @safe state) @safe + { + states_ ~= state; + } + /// Push a mark on the stack + void pushMark(Mark mark) @safe + { + marks_ ~= mark; + } + + /** + * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END + * implicit_document ::= block_node DOCUMENT-END* + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + */ + + ///Parse stream start. + Event parseStreamStart() @safe + { + const token = scanner_.front; + scanner_.popFront(); + state_ = &parseImplicitDocumentStart; + return streamStartEvent(token.startMark, token.endMark); + } + + /// Parse implicit document start, unless explicit detected: if so, parse explicit. + Event parseImplicitDocumentStart() @safe + { + // Parse an implicit document. + if(!scanner_.front.id.among!(TokenID.directive, TokenID.documentStart, + TokenID.streamEnd)) + { + tagDirectives_ = defaultTagDirectives_; + const token = scanner_.front; + + pushState(&parseDocumentEnd); + state_ = &parseBlockNode; + + return documentStartEvent(token.startMark, token.endMark, false, null, null); + } + return parseDocumentStart(); + } + + ///Parse explicit document start. + Event parseDocumentStart() @safe + { + //Parse any extra document end indicators. + while(scanner_.front.id == TokenID.documentEnd) + { + scanner_.popFront(); + } + + //Parse an explicit document. + if(scanner_.front.id != TokenID.streamEnd) + { + const startMark = scanner_.front.startMark; + + auto tagDirectives = processDirectives(); + enforce(scanner_.front.id == TokenID.documentStart, + new ParserException("Expected document start but found " ~ + scanner_.front.idString, + scanner_.front.startMark)); + + const endMark = scanner_.front.endMark; + scanner_.popFront(); + pushState(&parseDocumentEnd); + state_ = &parseDocumentContent; + return documentStartEvent(startMark, endMark, true, YAMLVersion_, tagDirectives); + } + else + { + //Parse the end of the stream. + const token = scanner_.front; + scanner_.popFront(); + assert(states_.data.length == 0); + assert(marks_.data.length == 0); + state_ = null; + return streamEndEvent(token.startMark, token.endMark); + } + } + + ///Parse document end (explicit or implicit). + Event parseDocumentEnd() @safe + { + Mark startMark = scanner_.front.startMark; + const bool explicit = scanner_.front.id == TokenID.documentEnd; + Mark endMark = startMark; + if (explicit) + { + endMark = scanner_.front.endMark; + scanner_.popFront(); + } + + state_ = &parseDocumentStart; + + return documentEndEvent(startMark, endMark, explicit); + } + + ///Parse document content. + Event parseDocumentContent() @safe + { + if(scanner_.front.id.among!(TokenID.directive, TokenID.documentStart, + TokenID.documentEnd, TokenID.streamEnd)) + { + state_ = popState(); + return processEmptyScalar(scanner_.front.startMark); + } + return parseBlockNode(); + } + + /// Process directives at the beginning of a document. + TagDirective[] processDirectives() @safe + { + // Destroy version and tag handles from previous document. + YAMLVersion_ = null; + tagDirectives_.length = 0; + + // Process directives. + while(scanner_.front.id == TokenID.directive) + { + const token = scanner_.front; + scanner_.popFront(); + string value = token.value.idup; + if(token.directive == DirectiveType.yaml) + { + enforce(YAMLVersion_ is null, + new ParserException("Duplicate YAML directive", token.startMark)); + const minor = value.split(".")[0]; + enforce(minor == "1", + new ParserException("Incompatible document (version 1.x is required)", + token.startMark)); + YAMLVersion_ = value; + } + else if(token.directive == DirectiveType.tag) + { + auto handle = value[0 .. token.valueDivider]; + + foreach(ref pair; tagDirectives_) + { + // handle + const h = pair.handle; + enforce(h != handle, new ParserException("Duplicate tag handle: " ~ handle, + token.startMark)); + } + tagDirectives_ ~= + TagDirective(handle, value[token.valueDivider .. $]); + } + // Any other directive type is ignored (only YAML and TAG are in YAML + // 1.1/1.2, any other directives are "reserved") + } + + TagDirective[] value = tagDirectives_; + + //Add any default tag handles that haven't been overridden. + foreach(ref defaultPair; defaultTagDirectives_) + { + bool found; + foreach(ref pair; tagDirectives_) if(defaultPair.handle == pair.handle) + { + found = true; + break; + } + if(!found) {tagDirectives_ ~= defaultPair; } + } + + return value; + } + + /** + * block_node_or_indentless_sequence ::= ALIAS + * | properties (block_content | indentless_block_sequence)? + * | block_content + * | indentless_block_sequence + * block_node ::= ALIAS + * | properties block_content? + * | block_content + * flow_node ::= ALIAS + * | properties flow_content? + * | flow_content + * properties ::= TAG ANCHOR? | ANCHOR TAG? + * block_content ::= block_collection | flow_collection | SCALAR + * flow_content ::= flow_collection | SCALAR + * block_collection ::= block_sequence | block_mapping + * flow_collection ::= flow_sequence | flow_mapping + */ + + ///Parse a node. + Event parseNode(const Flag!"block" block, + const Flag!"indentlessSequence" indentlessSequence = No.indentlessSequence) + @trusted + { + if(scanner_.front.id == TokenID.alias_) + { + const token = scanner_.front; + scanner_.popFront(); + state_ = popState(); + return aliasEvent(token.startMark, token.endMark, + cast(string)token.value); + } + + string anchor; + string tag; + Mark startMark, endMark, tagMark; + bool invalidMarks = true; + // The index in the tag string where tag handle ends and tag suffix starts. + uint tagHandleEnd; + + //Get anchor/tag if detected. Return false otherwise. + bool get(const TokenID id, const Flag!"first" first, ref string target) @safe + { + if(scanner_.front.id != id){return false;} + invalidMarks = false; + const token = scanner_.front; + scanner_.popFront(); + if(first){startMark = token.startMark;} + if(id == TokenID.tag) + { + tagMark = token.startMark; + tagHandleEnd = token.valueDivider; + } + endMark = token.endMark; + target = token.value.idup; + return true; + } + + //Anchor and/or tag can be in any order. + if(get(TokenID.anchor, Yes.first, anchor)){get(TokenID.tag, No.first, tag);} + else if(get(TokenID.tag, Yes.first, tag)) {get(TokenID.anchor, No.first, anchor);} + + if(tag !is null){tag = processTag(tag, tagHandleEnd, startMark, tagMark);} + + if(invalidMarks) + { + startMark = endMark = scanner_.front.startMark; + } + + bool implicit = (tag is null || tag == "!"); + + if(indentlessSequence && scanner_.front.id == TokenID.blockEntry) + { + state_ = &parseIndentlessSequenceEntry; + return sequenceStartEvent + (startMark, scanner_.front.endMark, anchor, + tag, implicit, CollectionStyle.block); + } + + if(scanner_.front.id == TokenID.scalar) + { + auto token = scanner_.front; + scanner_.popFront(); + auto value = token.style == ScalarStyle.doubleQuoted + ? handleDoubleQuotedScalarEscapes(token.value) + : cast(string)token.value; + + implicit = (token.style == ScalarStyle.plain && tag is null) || tag == "!"; + state_ = popState(); + return scalarEvent(startMark, token.endMark, anchor, tag, + implicit, value, token.style); + } + + if(scanner_.front.id == TokenID.flowSequenceStart) + { + endMark = scanner_.front.endMark; + state_ = &parseFlowSequenceEntry!(Yes.first); + return sequenceStartEvent(startMark, endMark, anchor, tag, + implicit, CollectionStyle.flow); + } + + if(scanner_.front.id == TokenID.flowMappingStart) + { + endMark = scanner_.front.endMark; + state_ = &parseFlowMappingKey!(Yes.first); + return mappingStartEvent(startMark, endMark, anchor, tag, + implicit, CollectionStyle.flow); + } + + if(block && scanner_.front.id == TokenID.blockSequenceStart) + { + endMark = scanner_.front.endMark; + state_ = &parseBlockSequenceEntry!(Yes.first); + return sequenceStartEvent(startMark, endMark, anchor, tag, + implicit, CollectionStyle.block); + } + + if(block && scanner_.front.id == TokenID.blockMappingStart) + { + endMark = scanner_.front.endMark; + state_ = &parseBlockMappingKey!(Yes.first); + return mappingStartEvent(startMark, endMark, anchor, tag, + implicit, CollectionStyle.block); + } + + if(anchor !is null || tag !is null) + { + state_ = popState(); + + //PyYAML uses a tuple(implicit, false) for the second last arg here, + //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 , ""); + } + + const token = scanner_.front; + throw new ParserException("While parsing a " ~ (block ? "block" : "flow") ~ " node", + startMark, "expected node content, but found: " + ~ token.idString, token.startMark); + } + + /// Handle escape sequences in a double quoted scalar. + /// + /// Moved here from scanner as it can't always be done in-place with slices. + string handleDoubleQuotedScalarEscapes(const(char)[] tokenValue) const @safe + { + string notInPlace; + bool inEscape; + auto appender = appender!(string)(); + for(const(char)[] oldValue = tokenValue; !oldValue.empty();) + { + const dchar c = oldValue.front(); + oldValue.popFront(); + + if(!inEscape) + { + if(c != '\\') + { + if(notInPlace is null) { appender.put(c); } + else { notInPlace ~= c; } + continue; + } + // Escape sequence starts with a '\' + inEscape = true; + continue; + } + + import dyaml.escapes; + scope(exit) { inEscape = false; } + + // 'Normal' escape sequence. + if(c.among!(escapes)) + { + if(notInPlace is null) + { + // \L and \C can't be handled in place as the expand into + // many-byte unicode chars + if(c != 'L' && c != 'P') + { + appender.put(dyaml.escapes.fromEscape(c)); + continue; + } + // Need to duplicate as we won't fit into + // token.value - which is what appender uses + notInPlace = appender.data.dup; + notInPlace ~= dyaml.escapes.fromEscape(c); + continue; + } + notInPlace ~= dyaml.escapes.fromEscape(c); + continue; + } + + // Unicode char written in hexadecimal in an escape sequence. + if(c.among!(escapeHexCodeList)) + { + // Scanner has already checked that the hex string is valid. + + const hexLength = dyaml.escapes.escapeHexLength(c); + // Any hex digits are 1-byte so this works. + const(char)[] hex = oldValue[0 .. hexLength]; + oldValue = oldValue[hexLength .. $]; + import std.ascii : isHexDigit; + assert(!hex.canFind!(d => !d.isHexDigit), + "Scanner must ensure the hex string is valid"); + + const decoded = cast(dchar)parse!int(hex, 16u); + if(notInPlace is null) { appender.put(decoded); } + else { notInPlace ~= decoded; } + continue; + } + + assert(false, "Scanner must handle unsupported escapes"); + } + + return notInPlace is null ? appender.data : notInPlace; + } + + /** + * Process a tag string retrieved from a tag token. + * + * Params: tag = Tag before processing. + * handleEnd = Index in tag where tag handle ends and tag suffix + * starts. + * startMark = Position of the node the tag belongs to. + * tagMark = Position of the tag. + */ + string processTag(const string tag, const uint handleEnd, + const Mark startMark, const Mark tagMark) + const @safe + { + const handle = tag[0 .. handleEnd]; + const suffix = tag[handleEnd .. $]; + + if(handle.length > 0) + { + string replacement; + foreach(ref pair; tagDirectives_) + { + if(pair.handle == handle) + { + replacement = pair.prefix; + break; + } + } + //handle must be in tagDirectives_ + enforce(replacement !is null, + new ParserException("While parsing a node", startMark, + "found undefined tag handle: " ~ handle, tagMark)); + return replacement ~ suffix; + } + return suffix; + } + + ///Wrappers to parse nodes. + Event parseBlockNode() @safe {return parseNode(Yes.block);} + Event parseFlowNode() @safe {return parseNode(No.block);} + Event parseBlockNodeOrIndentlessSequence() @safe {return parseNode(Yes.block, Yes.indentlessSequence);} + + ///block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END + + ///Parse an entry of a block sequence. If first is true, this is the first entry. + Event parseBlockSequenceEntry(Flag!"first" first)() @safe + { + static if(first) + { + pushMark(scanner_.front.startMark); + scanner_.popFront(); + } + + if(scanner_.front.id == TokenID.blockEntry) + { + const token = scanner_.front; + scanner_.popFront(); + if(!scanner_.front.id.among!(TokenID.blockEntry, TokenID.blockEnd)) + { + pushState(&parseBlockSequenceEntry!(No.first)); + return parseBlockNode(); + } + + state_ = &parseBlockSequenceEntry!(No.first); + return processEmptyScalar(token.endMark); + } + + if(scanner_.front.id != TokenID.blockEnd) + { + const token = scanner_.front; + throw new ParserException("While parsing a block collection", marks_.data.back, + "expected block end, but found " ~ token.idString, + token.startMark); + } + + state_ = popState(); + popMark(); + const token = scanner_.front; + scanner_.popFront(); + return sequenceEndEvent(token.startMark, token.endMark); + } + + ///indentless_sequence ::= (BLOCK-ENTRY block_node?)+ + + ///Parse an entry of an indentless sequence. + Event parseIndentlessSequenceEntry() @safe + { + if(scanner_.front.id == TokenID.blockEntry) + { + const token = scanner_.front; + scanner_.popFront(); + + if(!scanner_.front.id.among!(TokenID.blockEntry, TokenID.key, + TokenID.value, TokenID.blockEnd)) + { + pushState(&parseIndentlessSequenceEntry); + return parseBlockNode(); + } + + state_ = &parseIndentlessSequenceEntry; + return processEmptyScalar(token.endMark); + } + + state_ = popState(); + const token = scanner_.front; + return sequenceEndEvent(token.startMark, token.endMark); + } + + /** + * block_mapping ::= BLOCK-MAPPING_START + * ((KEY block_node_or_indentless_sequence?)? + * (VALUE block_node_or_indentless_sequence?)?)* + * BLOCK-END + */ + + ///Parse a key in a block mapping. If first is true, this is the first key. + Event parseBlockMappingKey(Flag!"first" first)() @safe + { + static if(first) + { + pushMark(scanner_.front.startMark); + scanner_.popFront(); + } + + if(scanner_.front.id == TokenID.key) + { + const token = scanner_.front; + scanner_.popFront(); + + if(!scanner_.front.id.among!(TokenID.key, TokenID.value, TokenID.blockEnd)) + { + pushState(&parseBlockMappingValue); + return parseBlockNodeOrIndentlessSequence(); + } + + state_ = &parseBlockMappingValue; + return processEmptyScalar(token.endMark); + } + + if(scanner_.front.id != TokenID.blockEnd) + { + const token = scanner_.front; + throw new ParserException("While parsing a block mapping", marks_.data.back, + "expected block end, but found: " ~ token.idString, + token.startMark); + } + + state_ = popState(); + popMark(); + const token = scanner_.front; + scanner_.popFront(); + return mappingEndEvent(token.startMark, token.endMark); + } + + ///Parse a value in a block mapping. + Event parseBlockMappingValue() @safe + { + if(scanner_.front.id == TokenID.value) + { + const token = scanner_.front; + scanner_.popFront(); + + if(!scanner_.front.id.among!(TokenID.key, TokenID.value, TokenID.blockEnd)) + { + pushState(&parseBlockMappingKey!(No.first)); + return parseBlockNodeOrIndentlessSequence(); + } + + state_ = &parseBlockMappingKey!(No.first); + return processEmptyScalar(token.endMark); + } + + state_= &parseBlockMappingKey!(No.first); + return processEmptyScalar(scanner_.front.startMark); + } + + /** + * flow_sequence ::= FLOW-SEQUENCE-START + * (flow_sequence_entry FLOW-ENTRY)* + * flow_sequence_entry? + * FLOW-SEQUENCE-END + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * + * Note that while production rules for both flow_sequence_entry and + * flow_mapping_entry are equal, their interpretations are different. + * For `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?` + * generate an inline mapping (set syntax). + */ + + ///Parse an entry in a flow sequence. If first is true, this is the first entry. + Event parseFlowSequenceEntry(Flag!"first" first)() @safe + { + static if(first) + { + pushMark(scanner_.front.startMark); + scanner_.popFront(); + } + + if(scanner_.front.id != TokenID.flowSequenceEnd) + { + static if(!first) + { + if(scanner_.front.id == TokenID.flowEntry) + { + scanner_.popFront(); + } + else + { + const token = scanner_.front; + throw new ParserException("While parsing a flow sequence", marks_.data.back, + "expected ',' or ']', but got: " ~ + token.idString, token.startMark); + } + } + + if(scanner_.front.id == TokenID.key) + { + const token = scanner_.front; + state_ = &parseFlowSequenceEntryMappingKey; + return mappingStartEvent(token.startMark, token.endMark, + null, null, true, CollectionStyle.flow); + } + else if(scanner_.front.id != TokenID.flowSequenceEnd) + { + pushState(&parseFlowSequenceEntry!(No.first)); + return parseFlowNode(); + } + } + + const token = scanner_.front; + scanner_.popFront(); + state_ = popState(); + popMark(); + return sequenceEndEvent(token.startMark, token.endMark); + } + + ///Parse a key in flow context. + Event parseFlowKey(Event delegate() @safe nextState) @safe + { + const token = scanner_.front; + scanner_.popFront(); + + if(!scanner_.front.id.among!(TokenID.value, TokenID.flowEntry, + TokenID.flowSequenceEnd)) + { + pushState(nextState); + return parseFlowNode(); + } + + state_ = nextState; + return processEmptyScalar(token.endMark); + } + + ///Parse a mapping key in an entry in a flow sequence. + Event parseFlowSequenceEntryMappingKey() @safe + { + return parseFlowKey(&parseFlowSequenceEntryMappingValue); + } + + ///Parse a mapping value in a flow context. + Event parseFlowValue(TokenID checkId, Event delegate() @safe nextState) + @safe + { + if(scanner_.front.id == TokenID.value) + { + const token = scanner_.front; + scanner_.popFront(); + if(!scanner_.front.id.among(TokenID.flowEntry, checkId)) + { + pushState(nextState); + return parseFlowNode(); + } + + state_ = nextState; + return processEmptyScalar(token.endMark); + } + + state_ = nextState; + return processEmptyScalar(scanner_.front.startMark); + } + + ///Parse a mapping value in an entry in a flow sequence. + Event parseFlowSequenceEntryMappingValue() @safe + { + return parseFlowValue(TokenID.flowSequenceEnd, + &parseFlowSequenceEntryMappingEnd); + } + + ///Parse end of a mapping in a flow sequence entry. + Event parseFlowSequenceEntryMappingEnd() @safe + { + state_ = &parseFlowSequenceEntry!(No.first); + const token = scanner_.front; + return mappingEndEvent(token.startMark, token.startMark); + } + + /** + * flow_mapping ::= FLOW-MAPPING-START + * (flow_mapping_entry FLOW-ENTRY)* + * flow_mapping_entry? + * FLOW-MAPPING-END + * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + */ + + ///Parse a key in a flow mapping. + Event parseFlowMappingKey(Flag!"first" first)() @safe + { + static if(first) + { + pushMark(scanner_.front.startMark); + scanner_.popFront(); + } + + if(scanner_.front.id != TokenID.flowMappingEnd) + { + static if(!first) + { + if(scanner_.front.id == TokenID.flowEntry) + { + scanner_.popFront(); + } + else + { + const token = scanner_.front; + throw new ParserException("While parsing a flow mapping", marks_.data.back, + "expected ',' or '}', but got: " ~ + token.idString, token.startMark); + } + } + + if(scanner_.front.id == TokenID.key) + { + return parseFlowKey(&parseFlowMappingValue); + } + + if(scanner_.front.id != TokenID.flowMappingEnd) + { + pushState(&parseFlowMappingEmptyValue); + return parseFlowNode(); + } + } + + const token = scanner_.front; + scanner_.popFront(); + state_ = popState(); + popMark(); + return mappingEndEvent(token.startMark, token.endMark); + } + + ///Parse a value in a flow mapping. + Event parseFlowMappingValue() @safe + { + return parseFlowValue(TokenID.flowMappingEnd, &parseFlowMappingKey!(No.first)); + } + + ///Parse an empty value in a flow mapping. + Event parseFlowMappingEmptyValue() @safe + { + state_ = &parseFlowMappingKey!(No.first); + return processEmptyScalar(scanner_.front.startMark); + } + + ///Return an empty scalar. + Event processEmptyScalar(const Mark mark) @safe pure nothrow const @nogc + { + return scalarEvent(mark, mark, null, null, true, ""); + } +} diff --git a/src/ext_depends/D-YAML/source/dyaml/queue.d b/src/ext_depends/D-YAML/source/dyaml/queue.d new file mode 100644 index 0000000..57b0d34 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/queue.d @@ -0,0 +1,272 @@ + +// Copyright Ferdinand Majerech 2011-2014. +// 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) + +module dyaml.queue; + + +import std.traits : hasMember, hasIndirections; + +package: + +/// Simple queue implemented as a singly linked list with a tail pointer. +/// +/// Needed in some D:YAML code that needs a queue-like structure without too much +/// reallocation that goes with an array. +/// +/// Allocations are non-GC and are damped by a free-list based on the nodes +/// that are removed. Note that elements lifetime must be managed +/// outside. +struct Queue(T) +if (!hasMember!(T, "__xdtor")) +{ + +private: + + // Linked list node containing one element and pointer to the next node. + struct Node + { + T payload_; + Node* next_; + } + + // Start of the linked list - first element added in time (end of the queue). + Node* first_; + // Last element of the linked list - last element added in time (start of the queue). + Node* last_; + // free-list + Node* stock; + + // Length of the queue. + size_t length_; + + // allocate a new node or recycle one from the stock. + Node* makeNewNode(T thePayload, Node* theNext = null) @trusted nothrow @nogc + { + import std.experimental.allocator : make; + import std.experimental.allocator.mallocator : Mallocator; + + Node* result; + if (stock !is null) + { + result = stock; + stock = result.next_; + result.payload_ = thePayload; + result.next_ = theNext; + } + else + { + result = Mallocator.instance.make!(Node)(thePayload, theNext); + // GC can dispose T managed member if it thinks they are no used... + static if (hasIndirections!T) + { + import core.memory : GC; + GC.addRange(result, Node.sizeof); + } + } + return result; + } + + // free the stock of available free nodes. + void freeStock() @trusted @nogc nothrow + { + import std.experimental.allocator.mallocator : Mallocator; + + while (stock !is null) + { + Node* toFree = stock; + stock = stock.next_; + static if (hasIndirections!T) + { + import core.memory : GC; + GC.removeRange(toFree); + } + Mallocator.instance.deallocate((cast(ubyte*) toFree)[0 .. Node.sizeof]); + } + } + +public: + + @disable void opAssign(ref Queue); + @disable bool opEquals(ref Queue); + @disable int opCmp(ref Queue); + + this(this) @safe nothrow @nogc + { + auto node = first_; + first_ = null; + last_ = null; + while (node !is null) + { + Node* newLast = makeNewNode(node.payload_); + if (last_ !is null) + last_.next_ = newLast; + if (first_ is null) + first_ = newLast; + last_ = newLast; + node = node.next_; + } + } + + ~this() @safe nothrow @nogc + { + freeStock(); + stock = first_; + freeStock(); + } + + /// Returns a forward range iterating over this queue. + auto range() @safe pure nothrow @nogc + { + static struct Result + { + private Node* cursor; + + void popFront() @safe pure nothrow @nogc + { + cursor = cursor.next_; + } + ref T front() @safe pure nothrow @nogc + in(cursor !is null) + { + return cursor.payload_; + } + bool empty() @safe pure nothrow @nogc const + { + return cursor is null; + } + } + return Result(first_); + } + + /// Push a new item to the queue. + void push(T item) @nogc @safe nothrow + { + Node* newLast = makeNewNode(item); + if (last_ !is null) + last_.next_ = newLast; + if (first_ is null) + first_ = newLast; + last_ = newLast; + ++length_; + } + + /// Insert a new item putting it to specified index in the linked list. + void insert(T item, const size_t idx) @safe nothrow + in + { + assert(idx <= length_); + } + do + { + if (idx == 0) + { + first_ = makeNewNode(item, first_); + ++length_; + } + // Adding before last added element, so we can just push. + else if (idx == length_) + { + push(item); + } + else + { + // Get the element before one we're inserting. + Node* current = first_; + foreach (i; 1 .. idx) + current = current.next_; + + assert(current); + // Insert a new node after current, and put current.next_ behind it. + current.next_ = makeNewNode(item, current.next_); + ++length_; + } + } + + /// Returns: The next element in the queue and remove it. + T pop() @safe nothrow + in + { + assert(!empty, "Trying to pop an element from an empty queue"); + } + do + { + T result = peek(); + + Node* oldStock = stock; + Node* old = first_; + first_ = first_.next_; + + // start the stock from the popped element + stock = old; + old.next_ = null; + // add the existing "old" stock to the new first stock element + if (oldStock !is null) + stock.next_ = oldStock; + + if (--length_ == 0) + { + assert(first_ is null); + last_ = null; + } + + return result; + } + + /// Returns: The next element in the queue. + ref inout(T) peek() @safe pure nothrow inout @nogc + in + { + assert(!empty, "Trying to peek at an element in an empty queue"); + } + do + { + return first_.payload_; + } + + /// Returns: true of the queue empty, false otherwise. + bool empty() @safe pure nothrow const @nogc + { + return first_ is null; + } + + /// Returns: The number of elements in the queue. + size_t length() @safe pure nothrow const @nogc + { + return length_; + } +} + +@safe nothrow unittest +{ + auto queue = Queue!int(); + assert(queue.empty); + foreach (i; 0 .. 65) + { + queue.push(5); + assert(queue.pop() == 5); + assert(queue.empty); + assert(queue.length_ == 0); + } + + int[] array = [1, -1, 2, -2, 3, -3, 4, -4, 5, -5]; + foreach (i; array) + { + queue.push(i); + } + + array = 42 ~ array[0 .. 3] ~ 42 ~ array[3 .. $] ~ 42; + queue.insert(42, 3); + queue.insert(42, 0); + queue.insert(42, queue.length); + + int[] array2; + while (!queue.empty) + { + array2 ~= queue.pop(); + } + + assert(array == array2); +} diff --git a/src/ext_depends/D-YAML/source/dyaml/reader.d b/src/ext_depends/D-YAML/source/dyaml/reader.d new file mode 100644 index 0000000..9fe42fc --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/reader.d @@ -0,0 +1,906 @@ + +// Copyright Ferdinand Majerech 2011-2014. +// 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) + +module dyaml.reader; + + +import core.stdc.stdlib; +import core.stdc.string; +import core.thread; + +import std.algorithm; +import std.array; +import std.conv; +import std.exception; +import std.range; +import std.string; +import std.system; +import std.typecons; +import std.utf; + +import tinyendian; + +import dyaml.encoding; +import dyaml.exception; + +alias isBreak = among!('\n', '\u0085', '\u2028', '\u2029'); + +package: + + +///Exception thrown at Reader errors. +class ReaderException : YAMLException +{ + this(string msg, string file = __FILE__, size_t line = __LINE__) + @safe pure nothrow + { + super("Reader error: " ~ msg, file, line); + } +} + +/// Provides an API to read characters from a UTF-8 buffer and build slices into that +/// buffer to avoid allocations (see SliceBuilder). +final class Reader +{ + private: + // Buffer of currently loaded characters. + char[] buffer_; + + // Current position within buffer. Only data after this position can be read. + size_t bufferOffset_; + + // Index of the current character in the buffer. + size_t charIndex_; + // Number of characters (code points) in buffer_. + size_t characterCount_; + + // File name + string name_; + // Current line in file. + uint line_; + // Current column in file. + uint column_; + + // Original Unicode encoding of the data. + Encoding encoding_; + + version(unittest) + { + // Endianness of the input before it was converted (for testing) + Endian endian_; + } + + // The number of consecutive ASCII characters starting at bufferOffset_. + // + // Used to minimize UTF-8 decoding. + size_t upcomingASCII_; + + // Index to buffer_ where the last decoded character starts. + size_t lastDecodedBufferOffset_; + // Offset, relative to charIndex_, of the last decoded character, + // in code points, not chars. + size_t lastDecodedCharOffset_; + + public: + /// Construct a Reader. + /// + /// Params: buffer = Buffer with YAML data. This may be e.g. the entire + /// contents of a file or a string. $(B will) be modified by + /// the Reader and other parts of D:YAML (D:YAML tries to + /// reuse the buffer to minimize memory allocations) + /// name = File name if the buffer is the contents of a file or + /// `"<unknown>"` if the buffer is the contents of a string. + /// + /// Throws: ReaderException on a UTF decoding error or if there are + /// nonprintable Unicode characters illegal in YAML. + this(ubyte[] buffer, string name = "<unknown>") @safe pure + { + name_ = name; + auto endianResult = fixUTFByteOrder(buffer); + if(endianResult.bytesStripped > 0) + { + throw new ReaderException("Size of UTF-16 or UTF-32 input not aligned " ~ + "to 2 or 4 bytes, respectively"); + } + + version(unittest) { endian_ = endianResult.endian; } + encoding_ = endianResult.encoding; + + auto utf8Result = toUTF8(endianResult.array, endianResult.encoding); + const msg = utf8Result.errorMessage; + if(msg !is null) + { + throw new ReaderException("Error when converting to UTF-8: " ~ msg); + } + + buffer_ = utf8Result.utf8; + + characterCount_ = utf8Result.characterCount; + // Check that all characters in buffer are printable. + enforce(isPrintableValidUTF8(buffer_), + new ReaderException("Special unicode characters are not allowed")); + + this.sliceBuilder = SliceBuilder(this); + checkASCII(); + } + + /// Get character at specified index relative to current position. + /// + /// Params: index = Index of the character to get relative to current position + /// in the buffer. Can point outside of the buffer; In that + /// case, '\0' will be returned. + /// + /// Returns: Character at specified position or '\0' if outside of the buffer. + /// + // XXX removed; search for 'risky' to find why. + // Throws: ReaderException if trying to read past the end of the buffer. + dchar peek(const size_t index) @safe pure + { + if(index < upcomingASCII_) { return buffer_[bufferOffset_ + index]; } + if(characterCount_ <= charIndex_ + index) + { + // XXX This is risky; revert this if bugs are introduced. We rely on + // the assumption that Reader only uses peek() to detect end of buffer. + // The test suite passes. + // Revert this case here and in other peek() versions if this causes + // errors. + // throw new ReaderException("Trying to read past the end of the buffer"); + return '\0'; + } + + // Optimized path for Scanner code that peeks chars in linear order to + // determine the length of some sequence. + if(index == lastDecodedCharOffset_) + { + ++lastDecodedCharOffset_; + const char b = buffer_[lastDecodedBufferOffset_]; + // ASCII + if(b < 0x80) + { + ++lastDecodedBufferOffset_; + return b; + } + return decode(buffer_, lastDecodedBufferOffset_); + } + + // 'Slow' path where we decode everything up to the requested character. + const asciiToTake = min(upcomingASCII_, index); + lastDecodedCharOffset_ = asciiToTake; + lastDecodedBufferOffset_ = bufferOffset_ + asciiToTake; + dchar d; + while(lastDecodedCharOffset_ <= index) + { + d = decodeNext(); + } + + return d; + } + + /// Optimized version of peek() for the case where peek index is 0. + dchar peek() @safe pure + { + if(upcomingASCII_ > 0) { return buffer_[bufferOffset_]; } + if(characterCount_ <= charIndex_) { return '\0'; } + + lastDecodedCharOffset_ = 0; + lastDecodedBufferOffset_ = bufferOffset_; + return decodeNext(); + } + + /// Get byte at specified index relative to current position. + /// + /// Params: index = Index of the byte to get relative to current position + /// in the buffer. Can point outside of the buffer; In that + /// case, '\0' will be returned. + /// + /// Returns: Byte at specified position or '\0' if outside of the buffer. + char peekByte(const size_t index) @safe pure nothrow @nogc + { + return characterCount_ > (charIndex_ + index) ? buffer_[bufferOffset_ + index] : '\0'; + } + + /// Optimized version of peekByte() for the case where peek byte index is 0. + char peekByte() @safe pure nothrow @nogc + { + return characterCount_ > charIndex_ ? buffer_[bufferOffset_] : '\0'; + } + + + /// Get specified number of characters starting at current position. + /// + /// Note: This gets only a "view" into the internal buffer, which will be + /// invalidated after other Reader calls. Use SliceBuilder to build slices + /// for permanent use. + /// + /// Params: length = Number of characters (code points, not bytes) to get. May + /// reach past the end of the buffer; in that case the returned + /// slice will be shorter. + /// + /// Returns: Characters starting at current position or an empty slice if out of bounds. + char[] prefix(const size_t length) @safe pure + { + return slice(length); + } + + /// Get specified number of bytes, not code points, starting at current position. + /// + /// Note: This gets only a "view" into the internal buffer, which will be + /// invalidated after other Reader calls. Use SliceBuilder to build slices + /// for permanent use. + /// + /// Params: length = Number bytes (not code points) to get. May NOT reach past + /// the end of the buffer; should be used with peek() to avoid + /// this. + /// + /// Returns: Bytes starting at current position. + char[] prefixBytes(const size_t length) @safe pure nothrow @nogc + in(length == 0 || bufferOffset_ + length <= buffer_.length, "prefixBytes out of bounds") + { + return buffer_[bufferOffset_ .. bufferOffset_ + length]; + } + + /// Get a slice view of the internal buffer, starting at the current position. + /// + /// Note: This gets only a "view" into the internal buffer, + /// which get invalidated after other Reader calls. + /// + /// Params: end = End of the slice relative to current position. May reach past + /// the end of the buffer; in that case the returned slice will + /// be shorter. + /// + /// Returns: Slice into the internal buffer or an empty slice if out of bounds. + char[] slice(const size_t end) @safe pure + { + // Fast path in case the caller has already peek()ed all the way to end. + if(end == lastDecodedCharOffset_) + { + return buffer_[bufferOffset_ .. lastDecodedBufferOffset_]; + } + + const asciiToTake = min(upcomingASCII_, end, buffer_.length); + lastDecodedCharOffset_ = asciiToTake; + lastDecodedBufferOffset_ = bufferOffset_ + asciiToTake; + + // 'Slow' path - decode everything up to end. + while(lastDecodedCharOffset_ < end && + lastDecodedBufferOffset_ < buffer_.length) + { + decodeNext(); + } + + return buffer_[bufferOffset_ .. lastDecodedBufferOffset_]; + } + + /// Get the next character, moving buffer position beyond it. + /// + /// Returns: Next character. + /// + /// Throws: ReaderException if trying to read past the end of the buffer + /// or if invalid data is read. + dchar get() @safe pure + { + const result = peek(); + forward(); + return result; + } + + /// Get specified number of characters, moving buffer position beyond them. + /// + /// Params: length = Number or characters (code points, not bytes) to get. + /// + /// Returns: Characters starting at current position. + char[] get(const size_t length) @safe pure + { + auto result = slice(length); + forward(length); + return result; + } + + /// Move current position forward. + /// + /// Params: length = Number of characters to move position forward. + void forward(size_t length) @safe pure + { + while(length > 0) + { + auto asciiToTake = min(upcomingASCII_, length); + charIndex_ += asciiToTake; + length -= asciiToTake; + upcomingASCII_ -= asciiToTake; + + for(; asciiToTake > 0; --asciiToTake) + { + const c = buffer_[bufferOffset_++]; + // c is ASCII, do we only need to check for ASCII line breaks. + if(c == '\n' || (c == '\r' && buffer_[bufferOffset_] != '\n')) + { + ++line_; + column_ = 0; + continue; + } + ++column_; + } + + // If we have used up all upcoming ASCII chars, the next char is + // non-ASCII even after this returns, so upcomingASCII_ doesn't need to + // be updated - it's zero. + if(length == 0) { break; } + + assert(upcomingASCII_ == 0, + "Running unicode handling code but we haven't run out of ASCII chars"); + assert(bufferOffset_ < buffer_.length, + "Attempted to decode past the end of YAML buffer"); + assert(buffer_[bufferOffset_] >= 0x80, + "ASCII must be handled by preceding code"); + + ++charIndex_; + const c = decode(buffer_, bufferOffset_); + + // New line. (can compare with '\n' without decoding since it's ASCII) + if(c.isBreak || (c == '\r' && buffer_[bufferOffset_] != '\n')) + { + ++line_; + column_ = 0; + } + else if(c != '\uFEFF') { ++column_; } + --length; + checkASCII(); + } + + lastDecodedBufferOffset_ = bufferOffset_; + lastDecodedCharOffset_ = 0; + } + + /// Move current position forward by one character. + void forward() @safe pure + { + ++charIndex_; + lastDecodedBufferOffset_ = bufferOffset_; + lastDecodedCharOffset_ = 0; + + // ASCII + if(upcomingASCII_ > 0) + { + --upcomingASCII_; + const c = buffer_[bufferOffset_++]; + + if(c == '\n' || (c == '\r' && buffer_[bufferOffset_] != '\n')) + { + ++line_; + column_ = 0; + return; + } + ++column_; + return; + } + + // UTF-8 + assert(bufferOffset_ < buffer_.length, + "Attempted to decode past the end of YAML buffer"); + assert(buffer_[bufferOffset_] >= 0x80, + "ASCII must be handled by preceding code"); + + const c = decode(buffer_, bufferOffset_); + + // New line. (can compare with '\n' without decoding since it's ASCII) + if(c.isBreak || (c == '\r' && buffer_[bufferOffset_] != '\n')) + { + ++line_; + column_ = 0; + } + else if(c != '\uFEFF') { ++column_; } + + checkASCII(); + } + + /// Used to build slices of read data in Reader; to avoid allocations. + SliceBuilder sliceBuilder; + + /// Get a string describing current buffer position, used for error messages. + Mark mark() const pure nothrow @nogc @safe { return Mark(name_, line_, column_); } + + /// Get file name. + string name() const @safe pure nothrow @nogc { return name_; } + + /// Get current line number. + uint line() const @safe pure nothrow @nogc { return line_; } + + /// Get current column number. + uint column() const @safe pure nothrow @nogc { return column_; } + + /// Get index of the current character in the buffer. + size_t charIndex() const @safe pure nothrow @nogc { return charIndex_; } + + /// Get encoding of the input buffer. + Encoding encoding() const @safe pure nothrow @nogc { return encoding_; } + +private: + // Update upcomingASCII_ (should be called forward()ing over a UTF-8 sequence) + void checkASCII() @safe pure nothrow @nogc + { + upcomingASCII_ = countASCII(buffer_[bufferOffset_ .. $]); + } + + // Decode the next character relative to + // lastDecodedCharOffset_/lastDecodedBufferOffset_ and update them. + // + // Does not advance the buffer position. Used in peek() and slice(). + dchar decodeNext() @safe pure + { + assert(lastDecodedBufferOffset_ < buffer_.length, + "Attempted to decode past the end of YAML buffer"); + const char b = buffer_[lastDecodedBufferOffset_]; + ++lastDecodedCharOffset_; + // ASCII + if(b < 0x80) + { + ++lastDecodedBufferOffset_; + return b; + } + + return decode(buffer_, lastDecodedBufferOffset_); + } +} + +/// Used to build slices of already read data in Reader buffer, avoiding allocations. +/// +/// Usually these slices point to unchanged Reader data, but sometimes the data is +/// changed due to how YAML interprets certain characters/strings. +/// +/// See begin() documentation. +struct SliceBuilder +{ +private: + // No copying by the user. + @disable this(this); + @disable void opAssign(ref SliceBuilder); + + // Reader this builder works in. + Reader reader_; + + // Start of the slice om reader_.buffer_ (size_t.max while no slice being build) + size_t start_ = size_t.max; + // End of the slice om reader_.buffer_ (size_t.max while no slice being build) + size_t end_ = size_t.max; + + // Stack of slice ends to revert to (see Transaction) + // + // Very few levels as we don't want arbitrarily nested transactions. + size_t[4] endStack_; + // The number of elements currently in endStack_. + size_t endStackUsed_; + + @safe const pure nothrow @nogc invariant() + { + if(!inProgress) { return; } + assert(end_ <= reader_.bufferOffset_, "Slice ends after buffer position"); + assert(start_ <= end_, "Slice start after slice end"); + } + + // Is a slice currently being built? + bool inProgress() @safe const pure nothrow @nogc + in(start_ == size_t.max ? end_ == size_t.max : end_ != size_t.max, "start_/end_ are not consistent") + { + return start_ != size_t.max; + } + +public: + /// Begin building a slice. + /// + /// Only one slice can be built at any given time; before beginning a new slice, + /// finish the previous one (if any). + /// + /// The slice starts at the current position in the Reader buffer. It can only be + /// extended up to the current position in the buffer; Reader methods get() and + /// forward() move the position. E.g. it is valid to extend a slice by write()-ing + /// a string just returned by get() - but not one returned by prefix() unless the + /// position has changed since the prefix() call. + void begin() @safe pure nothrow @nogc + in(!inProgress, "Beginning a slice while another slice is being built") + in(endStackUsed_ == 0, "Slice stack not empty at slice begin") + { + + start_ = reader_.bufferOffset_; + end_ = reader_.bufferOffset_; + } + + /// Finish building a slice and return it. + /// + /// Any Transactions on the slice must be committed or destroyed before the slice + /// is finished. + /// + /// Returns a string; once a slice is finished it is definitive that its contents + /// will not be changed. + char[] finish() @safe pure nothrow @nogc + in(inProgress, "finish called without begin") + in(endStackUsed_ == 0, "Finishing a slice with running transactions.") + { + + auto result = reader_.buffer_[start_ .. end_]; + start_ = end_ = size_t.max; + return result; + } + + /// Write a string to the slice being built. + /// + /// Data can only be written up to the current position in the Reader buffer. + /// + /// If str is a string returned by a Reader method, and str starts right after the + /// end of the slice being built, the slice is extended (trivial operation). + /// + /// See_Also: begin + void write(scope char[] str) @safe pure nothrow @nogc + { + assert(inProgress, "write called without begin"); + assert(end_ <= reader_.bufferOffset_, + "AT START: Slice ends after buffer position"); + + // Nothing? Already done. + if (str.length == 0) { return; } + // If str starts at the end of the slice (is a string returned by a Reader + // method), just extend the slice to contain str. + if(&str[0] == &reader_.buffer_[end_]) + { + end_ += str.length; + } + // Even if str does not start at the end of the slice, it still may be returned + // by a Reader method and point to buffer. So we need to memmove. + else + { + copy(str, reader_.buffer_[end_..end_ + str.length * char.sizeof]); + end_ += str.length; + } + } + + /// Write a character to the slice being built. + /// + /// Data can only be written up to the current position in the Reader buffer. + /// + /// See_Also: begin + void write(dchar c) @safe pure + in(inProgress, "write called without begin") + { + if(c < 0x80) + { + reader_.buffer_[end_++] = cast(char)c; + return; + } + + // We need to encode a non-ASCII dchar into UTF-8 + char[4] encodeBuf; + const bytes = encode(encodeBuf, c); + reader_.buffer_[end_ .. end_ + bytes] = encodeBuf[0 .. bytes]; + end_ += bytes; + } + + /// Insert a character to a specified position in the slice. + /// + /// Enlarges the slice by 1 char. Note that the slice can only extend up to the + /// current position in the Reader buffer. + /// + /// Params: + /// + /// c = The character to insert. + /// position = Position to insert the character at in code units, not code points. + /// Must be less than slice length(); a previously returned length() + /// can be used. + void insert(const dchar c, const size_t position) @safe pure + in(inProgress, "insert called without begin") + in(start_ + position <= end_, "Trying to insert after the end of the slice") + { + + const point = start_ + position; + const movedLength = end_ - point; + + // Encode c into UTF-8 + char[4] encodeBuf; + if(c < 0x80) { encodeBuf[0] = cast(char)c; } + const size_t bytes = c < 0x80 ? 1 : encode(encodeBuf, c); + + if(movedLength > 0) + { + copy(reader_.buffer_[point..point + movedLength * char.sizeof], + reader_.buffer_[point + bytes..point + bytes + movedLength * char.sizeof]); + } + reader_.buffer_[point .. point + bytes] = encodeBuf[0 .. bytes]; + end_ += bytes; + } + + /// Get the current length of the slice. + size_t length() @safe const pure nothrow @nogc + { + return end_ - start_; + } + + /// A slice building transaction. + /// + /// Can be used to save and revert back to slice state. + struct Transaction + { + private: + // The slice builder affected by the transaction. + SliceBuilder* builder_; + // Index of the return point of the transaction in StringBuilder.endStack_. + size_t stackLevel_; + // True after commit() has been called. + bool committed_; + + public: + /// Begins a transaction on a SliceBuilder object. + /// + /// The transaction must end $(B after) any transactions created within the + /// transaction but $(B before) the slice is finish()-ed. A transaction can be + /// ended either by commit()-ing or reverting through the destructor. + /// + /// Saves the current state of a slice. + this(SliceBuilder* builder) @safe pure nothrow @nogc + { + builder_ = builder; + stackLevel_ = builder_.endStackUsed_; + builder_.push(); + } + + /// Commit changes to the slice. + /// + /// Ends the transaction - can only be called once, and removes the possibility + /// to revert slice state. + /// + /// Does nothing for a default-initialized transaction (the transaction has not + /// been started yet). + void commit() @safe pure nothrow @nogc + in(!committed_, "Can't commit a transaction more than once") + { + + if(builder_ is null) { return; } + assert(builder_.endStackUsed_ == stackLevel_ + 1, + "Parent transactions don't fully contain child transactions"); + builder_.apply(); + committed_ = true; + } + + /// Destroy the transaction and revert it if it hasn't been committed yet. + void end() @safe pure nothrow @nogc + in(builder_ && builder_.endStackUsed_ == stackLevel_ + 1, "Parent transactions don't fully contain child transactions") + { + builder_.pop(); + builder_ = null; + } + + } + +private: + // Push the current end of the slice so we can revert to it if needed. + // + // Used by Transaction. + void push() @safe pure nothrow @nogc + in(inProgress, "push called without begin") + in(endStackUsed_ < endStack_.length, "Slice stack overflow") + { + endStack_[endStackUsed_++] = end_; + } + + // Pop the current end of endStack_ and set the end of the slice to the popped + // value, reverting changes since the old end was pushed. + // + // Used by Transaction. + void pop() @safe pure nothrow @nogc + in(inProgress, "pop called without begin") + in(endStackUsed_ > 0, "Trying to pop an empty slice stack") + { + end_ = endStack_[--endStackUsed_]; + } + + // Pop the current end of endStack_, but keep the current end of the slice, applying + // changes made since pushing the old end. + // + // Used by Transaction. + void apply() @safe pure nothrow @nogc + in(inProgress, "apply called without begin") + in(endStackUsed_ > 0, "Trying to apply an empty slice stack") + { + --endStackUsed_; + } +} + + +private: + +// Convert a UTF-8/16/32 buffer to UTF-8, in-place if possible. +// +// Params: +// +// input = Buffer with UTF-8/16/32 data to decode. May be overwritten by the +// conversion, in which case the result will be a slice of this buffer. +// encoding = Encoding of input. +// +// Returns: +// +// A struct with the following members: +// +// $(D string errorMessage) In case of an error, the error message is stored here. If +// there was no error, errorMessage is NULL. Always check +// this first. +// $(D char[] utf8) input converted to UTF-8. May be a slice of input. +// $(D size_t characterCount) Number of characters (code points) in input. +auto toUTF8(ubyte[] input, const UTFEncoding encoding) @safe pure nothrow +{ + // Documented in function ddoc. + struct Result + { + string errorMessage; + char[] utf8; + size_t characterCount; + } + + Result result; + + // Encode input_ into UTF-8 if it's encoded as UTF-16 or UTF-32. + // + // Params: + // + // buffer = The input buffer to encode. + // result = A Result struct to put encoded result and any error messages to. + // + // On error, result.errorMessage will be set. + static void encode(C)(C[] input, ref Result result) @safe pure + { + // We can do UTF-32->UTF-8 in place because all UTF-8 sequences are 4 or + // less bytes. + static if(is(C == dchar)) + { + char[4] encodeBuf; + auto utf8 = cast(char[])input; + auto length = 0; + foreach(dchar c; input) + { + ++result.characterCount; + // ASCII + if(c < 0x80) + { + utf8[length++] = cast(char)c; + continue; + } + + std.utf.encode(encodeBuf, c); + const bytes = codeLength!char(c); + utf8[length .. length + bytes] = encodeBuf[0 .. bytes]; + length += bytes; + } + result.utf8 = utf8[0 .. length]; + } + // Unfortunately we can't do UTF-16 in place so we just use std.conv.to + else + { + result.characterCount = std.utf.count(input); + result.utf8 = input.to!(char[]); + } + } + + try final switch(encoding) + { + case UTFEncoding.UTF_8: + result.utf8 = cast(char[])input; + result.utf8.validate(); + result.characterCount = std.utf.count(result.utf8); + break; + case UTFEncoding.UTF_16: + assert(input.length % 2 == 0, "UTF-16 buffer size must be even"); + encode(cast(wchar[])input, result); + break; + case UTFEncoding.UTF_32: + assert(input.length % 4 == 0, "UTF-32 buffer size must be a multiple of 4"); + encode(cast(dchar[])input, result); + break; + } + catch(ConvException e) { result.errorMessage = e.msg; } + catch(UTFException e) { result.errorMessage = e.msg; } + catch(Exception e) + { + assert(false, "Unexpected exception in encode(): " ~ e.msg); + } + + return result; +} + +/// Determine if all characters (code points, not bytes) in a string are printable. +bool isPrintableValidUTF8(const char[] chars) @safe pure +{ + import std.uni : isControl, isWhite; + foreach (dchar chr; chars) + { + if (!chr.isValidDchar || (chr.isControl && !chr.isWhite)) + { + return false; + } + } + return true; +} + +/// Counts the number of ASCII characters in buffer until the first UTF-8 sequence. +/// +/// Used to determine how many characters we can process without decoding. +size_t countASCII(const(char)[] buffer) @safe pure nothrow @nogc +{ + return buffer.byCodeUnit.until!(x => x > 0x7F).walkLength; +} +// Unittests. + +void testEndian(R)() +{ + void endian_test(ubyte[] data, Encoding encoding_expected, Endian endian_expected) + { + auto reader = new R(data); + assert(reader.encoding == encoding_expected); + assert(reader.endian_ == endian_expected); + } + ubyte[] little_endian_utf_16 = [0xFF, 0xFE, 0x7A, 0x00]; + ubyte[] big_endian_utf_16 = [0xFE, 0xFF, 0x00, 0x7A]; + endian_test(little_endian_utf_16, Encoding.UTF_16, Endian.littleEndian); + endian_test(big_endian_utf_16, Encoding.UTF_16, Endian.bigEndian); +} + +void testPeekPrefixForward(R)() +{ + import std.encoding; + ubyte[] data = bomTable[BOM.utf8].sequence ~ cast(ubyte[])"data"; + auto reader = new R(data); + assert(reader.peek() == 'd'); + assert(reader.peek(1) == 'a'); + assert(reader.peek(2) == 't'); + assert(reader.peek(3) == 'a'); + assert(reader.peek(4) == '\0'); + assert(reader.prefix(4) == "data"); + // assert(reader.prefix(6) == "data\0"); + reader.forward(2); + assert(reader.peek(1) == 'a'); + // assert(collectException(reader.peek(3))); +} + +void testUTF(R)() +{ + import std.encoding; + dchar[] data = cast(dchar[])"data"; + void utf_test(T)(T[] data, BOM bom) + { + ubyte[] bytes = bomTable[bom].sequence ~ + (cast(ubyte[])data)[0 .. data.length * T.sizeof]; + auto reader = new R(bytes); + assert(reader.peek() == 'd'); + assert(reader.peek(1) == 'a'); + assert(reader.peek(2) == 't'); + assert(reader.peek(3) == 'a'); + } + utf_test!char(to!(char[])(data), BOM.utf8); + utf_test!wchar(to!(wchar[])(data), endian == Endian.bigEndian ? BOM.utf16be : BOM.utf16le); + utf_test(data, endian == Endian.bigEndian ? BOM.utf32be : BOM.utf32le); +} + +void test1Byte(R)() +{ + ubyte[] data = [97]; + + auto reader = new R(data); + assert(reader.peek() == 'a'); + assert(reader.peek(1) == '\0'); + // assert(collectException(reader.peek(2))); +} + +@system unittest +{ + testEndian!Reader(); + testPeekPrefixForward!Reader(); + testUTF!Reader(); + test1Byte!Reader(); +} +//Issue 257 - https://github.com/dlang-community/D-YAML/issues/257 +@safe unittest +{ + import dyaml.loader : Loader; + auto yaml = "hello "; + auto root = Loader.fromString(yaml).load(); + + assert(root.isValid); +} diff --git a/src/ext_depends/D-YAML/source/dyaml/representer.d b/src/ext_depends/D-YAML/source/dyaml/representer.d new file mode 100644 index 0000000..a7ca802 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/representer.d @@ -0,0 +1,517 @@ + +// 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) + +/** + * YAML node _representer. Prepares YAML nodes for output. A tutorial can be + * found $(LINK2 ../tutorials/custom_types.html, here). + * + * Code based on $(LINK2 http://www.pyyaml.org, PyYAML). + */ +module dyaml.representer; + + +import std.algorithm; +import std.array; +import std.base64; +import std.container; +import std.conv; +import std.datetime; +import std.exception; +import std.format; +import std.math; +import std.typecons; +import std.string; + +import dyaml.exception; +import dyaml.node; +import dyaml.serializer; +import dyaml.style; + +package: +///Exception thrown on Representer errors. +class RepresenterException : YAMLException +{ + mixin ExceptionCtors; +} + +/** + * Represents YAML nodes as scalar, sequence and mapping nodes ready for output. + */ +Node representData(const Node data, ScalarStyle defaultScalarStyle, CollectionStyle defaultCollectionStyle) @safe +{ + Node result; + final switch(data.type) + { + case NodeType.null_: + result = representNull(); + break; + case NodeType.merge: + break; + case NodeType.boolean: + result = representBool(data); + break; + case NodeType.integer: + result = representLong(data); + break; + case NodeType.decimal: + result = representReal(data); + break; + case NodeType.binary: + result = representBytes(data); + break; + case NodeType.timestamp: + result = representSysTime(data); + break; + case NodeType.string: + result = representString(data); + break; + case NodeType.mapping: + result = representPairs(data, defaultScalarStyle, defaultCollectionStyle); + break; + case NodeType.sequence: + result = representNodes(data, defaultScalarStyle, defaultCollectionStyle); + break; + case NodeType.invalid: + assert(0); + } + + final switch (result.nodeID) + { + case NodeID.scalar: + if (result.scalarStyle == ScalarStyle.invalid) + { + result.scalarStyle = defaultScalarStyle; + } + break; + case NodeID.sequence, NodeID.mapping: + if (defaultCollectionStyle != CollectionStyle.invalid) + { + result.collectionStyle = defaultCollectionStyle; + } + case NodeID.invalid: + } + + + //Override tag if specified. + if(data.tag_ !is null){result.tag_ = data.tag_;} + + //Remember style if this was loaded before. + if(data.scalarStyle != ScalarStyle.invalid) + { + result.scalarStyle = data.scalarStyle; + } + if(data.collectionStyle != CollectionStyle.invalid) + { + result.collectionStyle = data.collectionStyle; + } + return result; +} + +@safe unittest +{ + // We don't emit yaml merge nodes. + assert(representData(Node(YAMLMerge()), ScalarStyle.invalid, CollectionStyle.invalid) == Node.init); +} + +@safe unittest +{ + assert(representData(Node(YAMLNull()), ScalarStyle.invalid, CollectionStyle.invalid) == Node("null", "tag:yaml.org,2002:null")); +} + +@safe unittest +{ + assert(representData(Node(cast(string)null), ScalarStyle.invalid, CollectionStyle.invalid) == Node("null", "tag:yaml.org,2002:null")); + assert(representData(Node("Hello world!"), ScalarStyle.invalid, CollectionStyle.invalid) == Node("Hello world!", "tag:yaml.org,2002:str")); +} + +@safe unittest +{ + assert(representData(Node(64), ScalarStyle.invalid, CollectionStyle.invalid) == Node("64", "tag:yaml.org,2002:int")); +} + +@safe unittest +{ + assert(representData(Node(true), ScalarStyle.invalid, CollectionStyle.invalid) == Node("true", "tag:yaml.org,2002:bool")); + assert(representData(Node(false), ScalarStyle.invalid, CollectionStyle.invalid) == Node("false", "tag:yaml.org,2002:bool")); +} + +@safe unittest +{ + // Float comparison is pretty unreliable... + auto result = representData(Node(1.0), ScalarStyle.invalid, CollectionStyle.invalid); + assert(approxEqual(result.as!string.to!real, 1.0)); + assert(result.tag == "tag:yaml.org,2002:float"); + + assert(representData(Node(real.nan), ScalarStyle.invalid, CollectionStyle.invalid) == Node(".nan", "tag:yaml.org,2002:float")); + assert(representData(Node(real.infinity), ScalarStyle.invalid, CollectionStyle.invalid) == Node(".inf", "tag:yaml.org,2002:float")); + assert(representData(Node(-real.infinity), ScalarStyle.invalid, CollectionStyle.invalid) == Node("-.inf", "tag:yaml.org,2002:float")); +} + +@safe unittest +{ + assert(representData(Node(SysTime(DateTime(2000, 3, 14, 12, 34, 56), UTC())), ScalarStyle.invalid, CollectionStyle.invalid) == Node("2000-03-14T12:34:56Z", "tag:yaml.org,2002:timestamp")); +} + +@safe unittest +{ + assert(representData(Node(Node[].init, "tag:yaml.org,2002:set"), ScalarStyle.invalid, CollectionStyle.invalid) == Node(Node.Pair[].init, "tag:yaml.org,2002:set")); + assert(representData(Node(Node[].init, "tag:yaml.org,2002:seq"), ScalarStyle.invalid, CollectionStyle.invalid) == Node(Node[].init, "tag:yaml.org,2002:seq")); + { + auto nodes = [ + Node("a"), + Node("b"), + Node("c"), + ]; + assert(representData(Node(nodes, "tag:yaml.org,2002:set"), ScalarStyle.invalid, CollectionStyle.invalid) == + Node([ + Node.Pair( + Node("a", "tag:yaml.org,2002:str"), + Node("null", "tag:yaml.org,2002:null") + ), + Node.Pair( + Node("b", "tag:yaml.org,2002:str"), + Node("null", "tag:yaml.org,2002:null") + ), + Node.Pair( + Node("c", "tag:yaml.org,2002:str"), + Node("null", "tag:yaml.org,2002:null") + ) + ], "tag:yaml.org,2002:set")); + } + { + auto nodes = [ + Node("a"), + Node("b"), + Node("c"), + ]; + assert(representData(Node(nodes, "tag:yaml.org,2002:seq"), ScalarStyle.invalid, CollectionStyle.invalid) == + Node([ + Node("a", "tag:yaml.org,2002:str"), + Node("b", "tag:yaml.org,2002:str"), + Node("c", "tag:yaml.org,2002:str") + ], "tag:yaml.org,2002:seq")); + } +} + +@safe unittest +{ + assert(representData(Node(Node.Pair[].init, "tag:yaml.org,2002:omap"), ScalarStyle.invalid, CollectionStyle.invalid) == Node(Node[].init, "tag:yaml.org,2002:omap")); + assert(representData(Node(Node.Pair[].init, "tag:yaml.org,2002:pairs"), ScalarStyle.invalid, CollectionStyle.invalid) == Node(Node[].init, "tag:yaml.org,2002:pairs")); + assert(representData(Node(Node.Pair[].init, "tag:yaml.org,2002:map"), ScalarStyle.invalid, CollectionStyle.invalid) == Node(Node.Pair[].init, "tag:yaml.org,2002:map")); + { + auto nodes = [ + Node.Pair("a", "b"), + Node.Pair("a", "c") + ]; + assertThrown(representData(Node(nodes, "tag:yaml.org,2002:omap"), ScalarStyle.invalid, CollectionStyle.invalid)); + } + // Yeah, this gets ugly really fast. + { + auto nodes = [ + Node.Pair("a", "b"), + Node.Pair("a", "c") + ]; + assert(representData(Node(nodes, "tag:yaml.org,2002:pairs"), ScalarStyle.invalid, CollectionStyle.invalid) == + Node([ + Node( + [Node.Pair( + Node("a", "tag:yaml.org,2002:str"), + Node("b", "tag:yaml.org,2002:str") + )], + "tag:yaml.org,2002:map"), + Node( + [Node.Pair( + Node("a", "tag:yaml.org,2002:str"), + Node("c", "tag:yaml.org,2002:str") + )], + "tag:yaml.org,2002:map"), + ], "tag:yaml.org,2002:pairs")); + } + { + auto nodes = [ + Node.Pair("a", "b"), + Node.Pair("a", "c") + ]; + assertThrown(representData(Node(nodes, "tag:yaml.org,2002:map"), ScalarStyle.invalid, CollectionStyle.invalid)); + } + { + auto nodes = [ + Node.Pair("a", "b"), + Node.Pair("c", "d") + ]; + assert(representData(Node(nodes, "tag:yaml.org,2002:omap"), ScalarStyle.invalid, CollectionStyle.invalid) == + Node([ + Node([ + Node.Pair( + Node("a", "tag:yaml.org,2002:str"), + Node("b", "tag:yaml.org,2002:str") + ) + ], "tag:yaml.org,2002:map"), + Node([ + Node.Pair( + Node("c", "tag:yaml.org,2002:str"), + Node("d", "tag:yaml.org,2002:str") + ) + ], "tag:yaml.org,2002:map" + )], "tag:yaml.org,2002:omap")); + } + { + auto nodes = [ + Node.Pair("a", "b"), + Node.Pair("c", "d") + ]; + assert(representData(Node(nodes, "tag:yaml.org,2002:map"), ScalarStyle.invalid, CollectionStyle.invalid) == + Node([ + Node.Pair( + Node("a", "tag:yaml.org,2002:str"), + Node("b", "tag:yaml.org,2002:str") + ), + Node.Pair( + Node("c", "tag:yaml.org,2002:str"), + Node("d", "tag:yaml.org,2002:str") + ), + ], "tag:yaml.org,2002:map")); + } +} + +private: + +//Represent a _null _node as a _null YAML value. +Node representNull() @safe +{ + return Node("null", "tag:yaml.org,2002:null"); +} + +//Represent a string _node as a string scalar. +Node representString(const Node node) @safe +{ + string value = node.as!string; + return value is null + ? Node("null", "tag:yaml.org,2002:null") + : Node(value, "tag:yaml.org,2002:str"); +} + +//Represent a bytes _node as a binary scalar. +Node representBytes(const Node node) @safe +{ + const ubyte[] value = node.as!(ubyte[]); + if(value is null){return Node("null", "tag:yaml.org,2002:null");} + + auto newNode = Node(Base64.encode(value).idup, "tag:yaml.org,2002:binary"); + newNode.scalarStyle = ScalarStyle.literal; + return newNode; +} + +//Represent a bool _node as a bool scalar. +Node representBool(const Node node) @safe +{ + return Node(node.as!bool ? "true" : "false", "tag:yaml.org,2002:bool"); +} + +//Represent a long _node as an integer scalar. +Node representLong(const Node node) @safe +{ + return Node(node.as!long.to!string, "tag:yaml.org,2002:int"); +} + +//Represent a real _node as a floating point scalar. +Node representReal(const Node node) @safe +{ + real f = node.as!real; + string value = isNaN(f) ? ".nan": + f == real.infinity ? ".inf": + f == -1.0 * real.infinity ? "-.inf": + {auto a = appender!string(); + formattedWrite(a, "%12f", f); + return a.data.strip();}(); + + return Node(value, "tag:yaml.org,2002:float"); +} + +//Represent a SysTime _node as a timestamp. +Node representSysTime(const Node node) @safe +{ + return Node(node.as!SysTime.toISOExtString(), "tag:yaml.org,2002:timestamp"); +} + +//Represent a sequence _node as sequence/set. +Node representNodes(const Node node, ScalarStyle defaultScalarStyle, CollectionStyle defaultCollectionStyle) @safe +{ + auto nodes = node.as!(Node[]); + if(node.tag_ == "tag:yaml.org,2002:set") + { + //YAML sets are mapping with null values. + Node.Pair[] pairs; + pairs.length = nodes.length; + + foreach(idx, key; nodes) + { + pairs[idx] = Node.Pair(key, Node("null", "tag:yaml.org,2002:null")); + } + Node.Pair[] value; + value.length = pairs.length; + + auto bestStyle = CollectionStyle.flow; + foreach(idx, pair; pairs) + { + value[idx] = Node.Pair(representData(pair.key, defaultScalarStyle, defaultCollectionStyle), representData(pair.value, defaultScalarStyle, defaultCollectionStyle)); + if(value[idx].shouldUseBlockStyle) + { + bestStyle = CollectionStyle.block; + } + } + + auto newNode = Node(value, node.tag_); + newNode.collectionStyle = bestStyle; + return newNode; + } + else + { + Node[] value; + value.length = nodes.length; + + auto bestStyle = CollectionStyle.flow; + foreach(idx, item; nodes) + { + value[idx] = representData(item, defaultScalarStyle, defaultCollectionStyle); + const isScalar = value[idx].nodeID == NodeID.scalar; + const s = value[idx].scalarStyle; + if(!isScalar || (s != ScalarStyle.invalid && s != ScalarStyle.plain)) + { + bestStyle = CollectionStyle.block; + } + } + + auto newNode = Node(value, "tag:yaml.org,2002:seq"); + newNode.collectionStyle = bestStyle; + return newNode; + } +} + +bool shouldUseBlockStyle(const Node value) @safe +{ + const isScalar = value.nodeID == NodeID.scalar; + const s = value.scalarStyle; + return (!isScalar || (s != ScalarStyle.invalid && s != ScalarStyle.plain)); +} +bool shouldUseBlockStyle(const Node.Pair value) @safe +{ + const keyScalar = value.key.nodeID == NodeID.scalar; + const valScalar = value.value.nodeID == NodeID.scalar; + const keyStyle = value.key.scalarStyle; + const valStyle = value.value.scalarStyle; + if(!keyScalar || + (keyStyle != ScalarStyle.invalid && keyStyle != ScalarStyle.plain)) + { + return true; + } + if(!valScalar || + (valStyle != ScalarStyle.invalid && valStyle != ScalarStyle.plain)) + { + return true; + } + return false; +} + +//Represent a mapping _node as map/ordered map/pairs. +Node representPairs(const Node node, ScalarStyle defaultScalarStyle, CollectionStyle defaultCollectionStyle) @safe +{ + auto pairs = node.as!(Node.Pair[]); + + bool hasDuplicates(const Node.Pair[] pairs) @safe + { + //TODO this should be replaced by something with deterministic memory allocation. + auto keys = redBlackTree!Node(); + foreach(pair; pairs) + { + if(pair.key in keys){return true;} + keys.insert(pair.key); + } + return false; + } + + Node[] mapToSequence(const Node.Pair[] pairs) @safe + { + Node[] nodes; + nodes.length = pairs.length; + foreach(idx, pair; pairs) + { + Node.Pair value; + + auto bestStyle = value.shouldUseBlockStyle ? CollectionStyle.block : CollectionStyle.flow; + value = Node.Pair(representData(pair.key, defaultScalarStyle, defaultCollectionStyle), representData(pair.value, defaultScalarStyle, defaultCollectionStyle)); + + auto newNode = Node([value], "tag:yaml.org,2002:map"); + newNode.collectionStyle = bestStyle; + nodes[idx] = newNode; + } + return nodes; + } + + if(node.tag_ == "tag:yaml.org,2002:omap") + { + enforce(!hasDuplicates(pairs), + new RepresenterException("Duplicate entry in an ordered map")); + auto sequence = mapToSequence(pairs); + Node[] value; + value.length = sequence.length; + + auto bestStyle = CollectionStyle.flow; + foreach(idx, item; sequence) + { + value[idx] = representData(item, defaultScalarStyle, defaultCollectionStyle); + if(value[idx].shouldUseBlockStyle) + { + bestStyle = CollectionStyle.block; + } + } + + auto newNode = Node(value, node.tag_); + newNode.collectionStyle = bestStyle; + return newNode; + } + else if(node.tag_ == "tag:yaml.org,2002:pairs") + { + auto sequence = mapToSequence(pairs); + Node[] value; + value.length = sequence.length; + + auto bestStyle = CollectionStyle.flow; + foreach(idx, item; sequence) + { + value[idx] = representData(item, defaultScalarStyle, defaultCollectionStyle); + if(value[idx].shouldUseBlockStyle) + { + bestStyle = CollectionStyle.block; + } + } + + auto newNode = Node(value, node.tag_); + newNode.collectionStyle = bestStyle; + return newNode; + } + else + { + enforce(!hasDuplicates(pairs), + new RepresenterException("Duplicate entry in an unordered map")); + Node.Pair[] value; + value.length = pairs.length; + + auto bestStyle = CollectionStyle.flow; + foreach(idx, pair; pairs) + { + value[idx] = Node.Pair(representData(pair.key, defaultScalarStyle, defaultCollectionStyle), representData(pair.value, defaultScalarStyle, defaultCollectionStyle)); + if(value[idx].shouldUseBlockStyle) + { + bestStyle = CollectionStyle.block; + } + } + + auto newNode = Node(value, "tag:yaml.org,2002:map"); + newNode.collectionStyle = bestStyle; + return newNode; + } +} 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_;} +} diff --git a/src/ext_depends/D-YAML/source/dyaml/scanner.d b/src/ext_depends/D-YAML/source/dyaml/scanner.d new file mode 100644 index 0000000..2009521 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/scanner.d @@ -0,0 +1,1788 @@ + +// Copyright Ferdinand Majerech 2011-2014. +// 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) + +/// YAML scanner. +/// Code based on PyYAML: http://www.pyyaml.org +module dyaml.scanner; + + +import core.stdc.string; + +import std.algorithm; +import std.array; +import std.conv; +import std.ascii : isAlphaNum, isDigit, isHexDigit; +import std.exception; +import std.string; +import std.typecons; +import std.traits : Unqual; +import std.utf; + +import dyaml.escapes; +import dyaml.exception; +import dyaml.queue; +import dyaml.reader; +import dyaml.style; +import dyaml.token; + +package: +/// Scanner produces tokens of the following types: +/// STREAM-START +/// STREAM-END +/// DIRECTIVE(name, value) +/// DOCUMENT-START +/// DOCUMENT-END +/// BLOCK-SEQUENCE-START +/// BLOCK-MAPPING-START +/// BLOCK-END +/// FLOW-SEQUENCE-START +/// FLOW-MAPPING-START +/// FLOW-SEQUENCE-END +/// FLOW-MAPPING-END +/// BLOCK-ENTRY +/// FLOW-ENTRY +/// KEY +/// VALUE +/// ALIAS(value) +/// ANCHOR(value) +/// TAG(value) +/// SCALAR(value, plain, style) + +alias isBreak = among!('\0', '\n', '\r', '\u0085', '\u2028', '\u2029'); + +alias isBreakOrSpace = among!(' ', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029'); + +alias isWhiteSpace = among!(' ', '\t', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029'); + +alias isNonLinebreakWhitespace = among!(' ', '\t'); + +alias isNonScalarStartCharacter = among!('-', '?', ':', ',', '[', ']', '{', '}', + '#', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`', ' ', '\t', '\0', '\n', + '\r', '\u0085', '\u2028', '\u2029'); + +alias isURIChar = among!('-', ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', + '_', '.', '!', '~', '*', '\'', '(', ')', '[', ']', '%'); + +alias isNSChar = among!(' ', '\n', '\r', '\u0085', '\u2028', '\u2029'); + +alias isBChar = among!('\n', '\r', '\u0085', '\u2028', '\u2029'); + +alias isFlowScalarBreakSpace = among!(' ', '\t', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029', '\'', '"', '\\'); + +/// Marked exception thrown at scanner errors. +/// +/// See_Also: MarkedYAMLException +class ScannerException : MarkedYAMLException +{ + mixin MarkedExceptionCtors; +} + +/// Generates tokens from data provided by a Reader. +struct Scanner +{ + private: + /// A simple key is a key that is not denoted by the '?' indicator. + /// For example: + /// --- + /// block simple key: value + /// ? not a simple key: + /// : { flow simple key: value } + /// We emit the KEY token before all keys, so when we find a potential simple + /// key, we try to locate the corresponding ':' indicator. Simple keys should be + /// limited to a single line and 1024 characters. + /// + /// 16 bytes on 64-bit. + static struct SimpleKey + { + /// Character index in reader where the key starts. + uint charIndex = uint.max; + /// Index of the key token from start (first token scanned being 0). + uint tokenIndex; + /// Line the key starts at. + uint line; + /// Column the key starts at. + ushort column; + /// Is this required to be a simple key? + bool required; + /// Is this struct "null" (invalid)?. + bool isNull; + } + + /// Block chomping types. + enum Chomping + { + /// Strip all trailing line breaks. '-' indicator. + strip, + /// Line break of the last line is preserved, others discarded. Default. + clip, + /// All trailing line breaks are preserved. '+' indicator. + keep + } + + /// Reader used to read from a file/stream. + Reader reader_; + /// Are we done scanning? + bool done_; + + /// Level of nesting in flow context. If 0, we're in block context. + uint flowLevel_; + /// Current indentation level. + int indent_ = -1; + /// Past indentation levels. Used as a stack. + Appender!(int[]) indents_; + + /// Processed tokens not yet emitted. Used as a queue. + Queue!Token tokens_; + + /// Number of tokens emitted through the getToken method. + uint tokensTaken_; + + /// Can a simple key start at the current position? A simple key may start: + /// - at the beginning of the line, not counting indentation spaces + /// (in block context), + /// - after '{', '[', ',' (in the flow context), + /// - after '?', ':', '-' (in the block context). + /// In the block context, this flag also signifies if a block collection + /// may start at the current position. + bool allowSimpleKey_ = true; + + /// Possible simple keys indexed by flow levels. + SimpleKey[] possibleSimpleKeys_; + + public: + /// Construct a Scanner using specified Reader. + this(Reader reader) @safe nothrow + { + // Return the next token, but do not delete it from the queue + reader_ = reader; + fetchStreamStart(); + } + + /// Advance to the next token + void popFront() @safe + { + ++tokensTaken_; + tokens_.pop(); + } + + /// Return the current token + const(Token) front() @safe + { + enforce(!empty, "No token left to peek"); + return tokens_.peek(); + } + + /// Return whether there are any more tokens left. + bool empty() @safe + { + while (needMoreTokens()) + { + fetchToken(); + } + return tokens_.empty; + } + + private: + /// Most scanning error messages have the same format; so build them with this + /// function. + string expected(T)(string expected, T found) + { + return text("expected ", expected, ", but found ", found); + } + + /// Determine whether or not we need to fetch more tokens before peeking/getting a token. + bool needMoreTokens() @safe pure + { + if(done_) { return false; } + if(tokens_.empty) { return true; } + + /// The current token may be a potential simple key, so we need to look further. + stalePossibleSimpleKeys(); + return nextPossibleSimpleKey() == tokensTaken_; + } + + /// Fetch at token, adding it to tokens_. + void fetchToken() @safe + { + // Eat whitespaces and comments until we reach the next token. + scanToNextToken(); + + // Remove obsolete possible simple keys. + stalePossibleSimpleKeys(); + + // Compare current indentation and column. It may add some tokens + // and decrease the current indentation level. + unwindIndent(reader_.column); + + // Get the next character. + const dchar c = reader_.peekByte(); + + // Fetch the token. + if(c == '\0') { return fetchStreamEnd(); } + if(checkDirective()) { return fetchDirective(); } + if(checkDocumentStart()) { return fetchDocumentStart(); } + if(checkDocumentEnd()) { return fetchDocumentEnd(); } + // Order of the following checks is NOT significant. + switch(c) + { + case '[': return fetchFlowSequenceStart(); + case '{': return fetchFlowMappingStart(); + case ']': return fetchFlowSequenceEnd(); + case '}': return fetchFlowMappingEnd(); + case ',': return fetchFlowEntry(); + case '!': return fetchTag(); + case '\'': return fetchSingle(); + case '\"': return fetchDouble(); + case '*': return fetchAlias(); + case '&': return fetchAnchor(); + case '?': if(checkKey()) { return fetchKey(); } goto default; + case ':': if(checkValue()) { return fetchValue(); } goto default; + case '-': if(checkBlockEntry()) { return fetchBlockEntry(); } goto default; + case '|': if(flowLevel_ == 0) { return fetchLiteral(); } break; + case '>': if(flowLevel_ == 0) { return fetchFolded(); } break; + default: if(checkPlain()) { return fetchPlain(); } + } + + throw new ScannerException("While scanning for the next token, found character " ~ + "\'%s\', index %s that cannot start any token" + .format(c, to!int(c)), reader_.mark); + } + + + /// Return the token number of the nearest possible simple key. + uint nextPossibleSimpleKey() @safe pure nothrow @nogc + { + uint minTokenNumber = uint.max; + foreach(k, ref simpleKey; possibleSimpleKeys_) + { + if(simpleKey.isNull) { continue; } + minTokenNumber = min(minTokenNumber, simpleKey.tokenIndex); + } + return minTokenNumber; + } + + /// Remove entries that are no longer possible simple keys. + /// + /// According to the YAML specification, simple keys + /// - should be limited to a single line, + /// - should be no longer than 1024 characters. + /// Disabling this will allow simple keys of any length and + /// height (may cause problems if indentation is broken though). + void stalePossibleSimpleKeys() @safe pure + { + foreach(level, ref key; possibleSimpleKeys_) + { + if(key.isNull) { continue; } + if(key.line != reader_.line || reader_.charIndex - key.charIndex > 1024) + { + enforce(!key.required, + new ScannerException("While scanning a simple key", + Mark(reader_.name, key.line, key.column), + "could not find expected ':'", reader_.mark)); + key.isNull = true; + } + } + } + + /// Check if the next token starts a possible simple key and if so, save its position. + /// + /// This function is called for ALIAS, ANCHOR, TAG, SCALAR(flow), '[', and '{'. + void savePossibleSimpleKey() @safe pure + { + // Check if a simple key is required at the current position. + const required = (flowLevel_ == 0 && indent_ == reader_.column); + assert(allowSimpleKey_ || !required, "A simple key is required only if it is " ~ + "the first token in the current line. Therefore it is always allowed."); + + if(!allowSimpleKey_) { return; } + + // The next token might be a simple key, so save its number and position. + removePossibleSimpleKey(); + const tokenCount = tokensTaken_ + cast(uint)tokens_.length; + + const line = reader_.line; + const column = reader_.column; + const key = SimpleKey(cast(uint)reader_.charIndex, tokenCount, line, + cast(ushort)min(column, ushort.max), required); + + if(possibleSimpleKeys_.length <= flowLevel_) + { + const oldLength = possibleSimpleKeys_.length; + possibleSimpleKeys_.length = flowLevel_ + 1; + //No need to initialize the last element, it's already done in the next line. + possibleSimpleKeys_[oldLength .. flowLevel_] = SimpleKey.init; + } + possibleSimpleKeys_[flowLevel_] = key; + } + + /// Remove the saved possible key position at the current flow level. + void removePossibleSimpleKey() @safe pure + { + if(possibleSimpleKeys_.length <= flowLevel_) { return; } + + if(!possibleSimpleKeys_[flowLevel_].isNull) + { + const key = possibleSimpleKeys_[flowLevel_]; + enforce(!key.required, + new ScannerException("While scanning a simple key", + Mark(reader_.name, key.line, key.column), + "could not find expected ':'", reader_.mark)); + possibleSimpleKeys_[flowLevel_].isNull = true; + } + } + + /// Decrease indentation, removing entries in indents_. + /// + /// Params: column = Current column in the file/stream. + void unwindIndent(const int column) @safe + { + if(flowLevel_ > 0) + { + // In flow context, tokens should respect indentation. + // The condition should be `indent >= column` according to the spec. + // But this condition will prohibit intuitively correct + // constructions such as + // key : { + // } + + // In the flow context, indentation is ignored. We make the scanner less + // restrictive than what the specification requires. + // if(pedantic_ && flowLevel_ > 0 && indent_ > column) + // { + // throw new ScannerException("Invalid intendation or unclosed '[' or '{'", + // reader_.mark) + // } + return; + } + + // In block context, we may need to issue the BLOCK-END tokens. + while(indent_ > column) + { + indent_ = indents_.data.back; + assert(indents_.data.length); + indents_.shrinkTo(indents_.data.length - 1); + tokens_.push(blockEndToken(reader_.mark, reader_.mark)); + } + } + + /// Increase indentation if needed. + /// + /// Params: column = Current column in the file/stream. + /// + /// Returns: true if the indentation was increased, false otherwise. + bool addIndent(int column) @safe + { + if(indent_ >= column){return false;} + indents_ ~= indent_; + indent_ = column; + return true; + } + + + /// Add STREAM-START token. + void fetchStreamStart() @safe nothrow + { + tokens_.push(streamStartToken(reader_.mark, reader_.mark, reader_.encoding)); + } + + ///Add STREAM-END token. + void fetchStreamEnd() @safe + { + //Set intendation to -1 . + unwindIndent(-1); + removePossibleSimpleKey(); + allowSimpleKey_ = false; + possibleSimpleKeys_.destroy; + + tokens_.push(streamEndToken(reader_.mark, reader_.mark)); + done_ = true; + } + + /// Add DIRECTIVE token. + void fetchDirective() @safe + { + // Set intendation to -1 . + unwindIndent(-1); + // Reset simple keys. + removePossibleSimpleKey(); + allowSimpleKey_ = false; + + auto directive = scanDirective(); + tokens_.push(directive); + } + + /// Add DOCUMENT-START or DOCUMENT-END token. + void fetchDocumentIndicator(TokenID id)() + if(id == TokenID.documentStart || id == TokenID.documentEnd) + { + // Set indentation to -1 . + unwindIndent(-1); + // Reset simple keys. Note that there can't be a block collection after '---'. + removePossibleSimpleKey(); + allowSimpleKey_ = false; + + Mark startMark = reader_.mark; + reader_.forward(3); + tokens_.push(simpleToken!id(startMark, reader_.mark)); + } + + /// Aliases to add DOCUMENT-START or DOCUMENT-END token. + alias fetchDocumentStart = fetchDocumentIndicator!(TokenID.documentStart); + alias fetchDocumentEnd = fetchDocumentIndicator!(TokenID.documentEnd); + + /// Add FLOW-SEQUENCE-START or FLOW-MAPPING-START token. + void fetchFlowCollectionStart(TokenID id)() @safe + { + // '[' and '{' may start a simple key. + savePossibleSimpleKey(); + // Simple keys are allowed after '[' and '{'. + allowSimpleKey_ = true; + ++flowLevel_; + + Mark startMark = reader_.mark; + reader_.forward(); + tokens_.push(simpleToken!id(startMark, reader_.mark)); + } + + /// Aliases to add FLOW-SEQUENCE-START or FLOW-MAPPING-START token. + alias fetchFlowSequenceStart = fetchFlowCollectionStart!(TokenID.flowSequenceStart); + alias fetchFlowMappingStart = fetchFlowCollectionStart!(TokenID.flowMappingStart); + + /// Add FLOW-SEQUENCE-START or FLOW-MAPPING-START token. + void fetchFlowCollectionEnd(TokenID id)() + { + // Reset possible simple key on the current level. + removePossibleSimpleKey(); + // No simple keys after ']' and '}'. + allowSimpleKey_ = false; + --flowLevel_; + + Mark startMark = reader_.mark; + reader_.forward(); + tokens_.push(simpleToken!id(startMark, reader_.mark)); + } + + /// Aliases to add FLOW-SEQUENCE-START or FLOW-MAPPING-START token/ + alias fetchFlowSequenceEnd = fetchFlowCollectionEnd!(TokenID.flowSequenceEnd); + alias fetchFlowMappingEnd = fetchFlowCollectionEnd!(TokenID.flowMappingEnd); + + /// Add FLOW-ENTRY token; + void fetchFlowEntry() @safe + { + // Reset possible simple key on the current level. + removePossibleSimpleKey(); + // Simple keys are allowed after ','. + allowSimpleKey_ = true; + + Mark startMark = reader_.mark; + reader_.forward(); + tokens_.push(flowEntryToken(startMark, reader_.mark)); + } + + /// Additional checks used in block context in fetchBlockEntry and fetchKey. + /// + /// Params: type = String representing the token type we might need to add. + /// id = Token type we might need to add. + void blockChecks(string type, TokenID id)() + { + enum context = type ~ " keys are not allowed here"; + // Are we allowed to start a key (not neccesarily a simple one)? + enforce(allowSimpleKey_, new ScannerException(context, reader_.mark)); + + if(addIndent(reader_.column)) + { + tokens_.push(simpleToken!id(reader_.mark, reader_.mark)); + } + } + + /// Add BLOCK-ENTRY token. Might add BLOCK-SEQUENCE-START in the process. + void fetchBlockEntry() @safe + { + if(flowLevel_ == 0) { blockChecks!("Sequence", TokenID.blockSequenceStart)(); } + + // It's an error for the block entry to occur in the flow context, + // but we let the parser detect this. + + // Reset possible simple key on the current level. + removePossibleSimpleKey(); + // Simple keys are allowed after '-'. + allowSimpleKey_ = true; + + Mark startMark = reader_.mark; + reader_.forward(); + tokens_.push(blockEntryToken(startMark, reader_.mark)); + } + + /// Add KEY token. Might add BLOCK-MAPPING-START in the process. + void fetchKey() @safe + { + if(flowLevel_ == 0) { blockChecks!("Mapping", TokenID.blockMappingStart)(); } + + // Reset possible simple key on the current level. + removePossibleSimpleKey(); + // Simple keys are allowed after '?' in the block context. + allowSimpleKey_ = (flowLevel_ == 0); + + Mark startMark = reader_.mark; + reader_.forward(); + tokens_.push(keyToken(startMark, reader_.mark)); + } + + /// Add VALUE token. Might add KEY and/or BLOCK-MAPPING-START in the process. + void fetchValue() @safe + { + //Do we determine a simple key? + if(possibleSimpleKeys_.length > flowLevel_ && + !possibleSimpleKeys_[flowLevel_].isNull) + { + const key = possibleSimpleKeys_[flowLevel_]; + possibleSimpleKeys_[flowLevel_].isNull = true; + Mark keyMark = Mark(reader_.name, key.line, key.column); + const idx = key.tokenIndex - tokensTaken_; + + assert(idx >= 0); + + // Add KEY. + // Manually inserting since tokens are immutable (need linked list). + tokens_.insert(keyToken(keyMark, keyMark), idx); + + // If this key starts a new block mapping, we need to add BLOCK-MAPPING-START. + if(flowLevel_ == 0 && addIndent(key.column)) + { + tokens_.insert(blockMappingStartToken(keyMark, keyMark), idx); + } + + // There cannot be two simple keys in a row. + allowSimpleKey_ = false; + } + // Part of a complex key + else + { + // We can start a complex value if and only if we can start a simple key. + enforce(flowLevel_ > 0 || allowSimpleKey_, + new ScannerException("Mapping values are not allowed here", reader_.mark)); + + // If this value starts a new block mapping, we need to add + // BLOCK-MAPPING-START. It'll be detected as an error later by the parser. + if(flowLevel_ == 0 && addIndent(reader_.column)) + { + tokens_.push(blockMappingStartToken(reader_.mark, reader_.mark)); + } + + // Reset possible simple key on the current level. + removePossibleSimpleKey(); + // Simple keys are allowed after ':' in the block context. + allowSimpleKey_ = (flowLevel_ == 0); + } + + // Add VALUE. + Mark startMark = reader_.mark; + reader_.forward(); + tokens_.push(valueToken(startMark, reader_.mark)); + } + + /// Add ALIAS or ANCHOR token. + void fetchAnchor_(TokenID id)() @safe + if(id == TokenID.alias_ || id == TokenID.anchor) + { + // ALIAS/ANCHOR could be a simple key. + savePossibleSimpleKey(); + // No simple keys after ALIAS/ANCHOR. + allowSimpleKey_ = false; + + auto anchor = scanAnchor(id); + tokens_.push(anchor); + } + + /// Aliases to add ALIAS or ANCHOR token. + alias fetchAlias = fetchAnchor_!(TokenID.alias_); + alias fetchAnchor = fetchAnchor_!(TokenID.anchor); + + /// Add TAG token. + void fetchTag() @safe + { + //TAG could start a simple key. + savePossibleSimpleKey(); + //No simple keys after TAG. + allowSimpleKey_ = false; + + tokens_.push(scanTag()); + } + + /// Add block SCALAR token. + void fetchBlockScalar(ScalarStyle style)() @safe + if(style == ScalarStyle.literal || style == ScalarStyle.folded) + { + // Reset possible simple key on the current level. + removePossibleSimpleKey(); + // A simple key may follow a block scalar. + allowSimpleKey_ = true; + + auto blockScalar = scanBlockScalar(style); + tokens_.push(blockScalar); + } + + /// Aliases to add literal or folded block scalar. + alias fetchLiteral = fetchBlockScalar!(ScalarStyle.literal); + alias fetchFolded = fetchBlockScalar!(ScalarStyle.folded); + + /// Add quoted flow SCALAR token. + void fetchFlowScalar(ScalarStyle quotes)() + { + // A flow scalar could be a simple key. + savePossibleSimpleKey(); + // No simple keys after flow scalars. + allowSimpleKey_ = false; + + // Scan and add SCALAR. + auto scalar = scanFlowScalar(quotes); + tokens_.push(scalar); + } + + /// Aliases to add single or double quoted block scalar. + alias fetchSingle = fetchFlowScalar!(ScalarStyle.singleQuoted); + alias fetchDouble = fetchFlowScalar!(ScalarStyle.doubleQuoted); + + /// Add plain SCALAR token. + void fetchPlain() @safe + { + // A plain scalar could be a simple key + savePossibleSimpleKey(); + // No simple keys after plain scalars. But note that scanPlain() will + // change this flag if the scan is finished at the beginning of the line. + allowSimpleKey_ = false; + auto plain = scanPlain(); + + // Scan and add SCALAR. May change allowSimpleKey_ + tokens_.push(plain); + } + + pure: + + ///Check if the next token is DIRECTIVE: ^ '%' ... + bool checkDirective() @safe + { + return reader_.peekByte() == '%' && reader_.column == 0; + } + + /// Check if the next token is DOCUMENT-START: ^ '---' (' '|'\n') + bool checkDocumentStart() @safe + { + // Check one char first, then all 3, to prevent reading outside the buffer. + return reader_.column == 0 && + reader_.peekByte() == '-' && + reader_.prefix(3) == "---" && + reader_.peek(3).isWhiteSpace; + } + + /// Check if the next token is DOCUMENT-END: ^ '...' (' '|'\n') + bool checkDocumentEnd() @safe + { + // Check one char first, then all 3, to prevent reading outside the buffer. + return reader_.column == 0 && + reader_.peekByte() == '.' && + reader_.prefix(3) == "..." && + reader_.peek(3).isWhiteSpace; + } + + /// Check if the next token is BLOCK-ENTRY: '-' (' '|'\n') + bool checkBlockEntry() @safe + { + return !!reader_.peek(1).isWhiteSpace; + } + + /// Check if the next token is KEY(flow context): '?' + /// + /// or KEY(block context): '?' (' '|'\n') + bool checkKey() @safe + { + return (flowLevel_ > 0 || reader_.peek(1).isWhiteSpace); + } + + /// Check if the next token is VALUE(flow context): ':' + /// + /// or VALUE(block context): ':' (' '|'\n') + bool checkValue() @safe + { + return flowLevel_ > 0 || reader_.peek(1).isWhiteSpace; + } + + /// Check if the next token is a plain scalar. + /// + /// A plain scalar may start with any non-space character except: + /// '-', '?', ':', ',', '[', ']', '{', '}', + /// '#', '&', '*', '!', '|', '>', '\'', '\"', + /// '%', '@', '`'. + /// + /// It may also start with + /// '-', '?', ':' + /// if it is followed by a non-space character. + /// + /// Note that we limit the last rule to the block context (except the + /// '-' character) because we want the flow context to be space + /// independent. + bool checkPlain() @safe + { + const c = reader_.peek(); + if(!c.isNonScalarStartCharacter) + { + return true; + } + return !reader_.peek(1).isWhiteSpace && + (c == '-' || (flowLevel_ == 0 && (c == '?' || c == ':'))); + } + + /// Move to the next non-space character. + void findNextNonSpace() @safe + { + while(reader_.peekByte() == ' ') { reader_.forward(); } + } + + /// Scan a string of alphanumeric or "-_" characters. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// characters into that slice. + void scanAlphaNumericToSlice(string name)(const Mark startMark) + { + size_t length; + dchar c = reader_.peek(); + while(c.isAlphaNum || c.among!('-', '_')) { c = reader_.peek(++length); } + + enforce(length > 0, new ScannerException("While scanning " ~ name, + startMark, expected("alphanumeric, '-' or '_'", c), reader_.mark)); + + reader_.sliceBuilder.write(reader_.get(length)); + } + + /// Scan and throw away all characters until next line break. + void scanToNextBreak() @safe + { + while(!reader_.peek().isBreak) { reader_.forward(); } + } + + /// Scan all characters until next line break. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// characters into that slice. + void scanToNextBreakToSlice() @safe + { + uint length; + while(!reader_.peek(length).isBreak) + { + ++length; + } + reader_.sliceBuilder.write(reader_.get(length)); + } + + + /// Move to next token in the file/stream. + /// + /// We ignore spaces, line breaks and comments. + /// If we find a line break in the block context, we set + /// allowSimpleKey` on. + /// + /// We do not yet support BOM inside the stream as the + /// specification requires. Any such mark will be considered as a part + /// of the document. + void scanToNextToken() @safe + { + // TODO(PyYAML): We need to make tab handling rules more sane. A good rule is: + // Tabs cannot precede tokens + // BLOCK-SEQUENCE-START, BLOCK-MAPPING-START, BLOCK-END, + // KEY(block), VALUE(block), BLOCK-ENTRY + // So the checking code is + // if <TAB>: + // allowSimpleKey_ = false + // We also need to add the check for `allowSimpleKey_ == true` to + // `unwindIndent` before issuing BLOCK-END. + // Scanners for block, flow, and plain scalars need to be modified. + + for(;;) + { + //All whitespace in flow context is ignored, even whitespace + // not allowed in other contexts + if (flowLevel_ > 0) + { + while(reader_.peekByte().isNonLinebreakWhitespace) { reader_.forward(); } + } + else + { + findNextNonSpace(); + } + if(reader_.peekByte() == '#') { scanToNextBreak(); } + if(scanLineBreak() != '\0') + { + if(flowLevel_ == 0) { allowSimpleKey_ = true; } + } + else + { + break; + } + } + } + + /// Scan directive token. + Token scanDirective() @safe + { + Mark startMark = reader_.mark; + // Skip the '%'. + reader_.forward(); + + // Scan directive name + reader_.sliceBuilder.begin(); + scanDirectiveNameToSlice(startMark); + const name = reader_.sliceBuilder.finish(); + + reader_.sliceBuilder.begin(); + + // Index where tag handle ends and suffix starts in a tag directive value. + uint tagHandleEnd = uint.max; + if(name == "YAML") { scanYAMLDirectiveValueToSlice(startMark); } + else if(name == "TAG") { tagHandleEnd = scanTagDirectiveValueToSlice(startMark); } + char[] value = reader_.sliceBuilder.finish(); + + Mark endMark = reader_.mark; + + DirectiveType directive; + if(name == "YAML") { directive = DirectiveType.yaml; } + else if(name == "TAG") { directive = DirectiveType.tag; } + else + { + directive = DirectiveType.reserved; + scanToNextBreak(); + } + + scanDirectiveIgnoredLine(startMark); + + return directiveToken(startMark, endMark, value, directive, tagHandleEnd); + } + + /// Scan name of a directive token. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// characters into that slice. + void scanDirectiveNameToSlice(const Mark startMark) @safe + { + // Scan directive name. + scanAlphaNumericToSlice!"a directive"(startMark); + + enforce(reader_.peek().among!(' ', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029'), + new ScannerException("While scanning a directive", startMark, + expected("alphanumeric, '-' or '_'", reader_.peek()), reader_.mark)); + } + + /// Scan value of a YAML directive token. Returns major, minor version separated by '.'. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// characters into that slice. + void scanYAMLDirectiveValueToSlice(const Mark startMark) @safe + { + findNextNonSpace(); + + scanYAMLDirectiveNumberToSlice(startMark); + + enforce(reader_.peekByte() == '.', + new ScannerException("While scanning a directive", startMark, + expected("digit or '.'", reader_.peek()), reader_.mark)); + // Skip the '.'. + reader_.forward(); + + reader_.sliceBuilder.write('.'); + scanYAMLDirectiveNumberToSlice(startMark); + + enforce(reader_.peek().among!(' ', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029'), + new ScannerException("While scanning a directive", startMark, + expected("digit or '.'", reader_.peek()), reader_.mark)); + } + + /// Scan a number from a YAML directive. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// characters into that slice. + void scanYAMLDirectiveNumberToSlice(const Mark startMark) @safe + { + enforce(isDigit(reader_.peek()), + new ScannerException("While scanning a directive", startMark, + expected("digit", reader_.peek()), reader_.mark)); + + // Already found the first digit in the enforce(), so set length to 1. + uint length = 1; + while(reader_.peek(length).isDigit) { ++length; } + + reader_.sliceBuilder.write(reader_.get(length)); + } + + /// Scan value of a tag directive. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// characters into that slice. + /// + /// Returns: Length of tag handle (which is before tag prefix) in scanned data + uint scanTagDirectiveValueToSlice(const Mark startMark) @safe + { + findNextNonSpace(); + const startLength = reader_.sliceBuilder.length; + scanTagDirectiveHandleToSlice(startMark); + const handleLength = cast(uint)(reader_.sliceBuilder.length - startLength); + findNextNonSpace(); + scanTagDirectivePrefixToSlice(startMark); + + return handleLength; + } + + /// Scan handle of a tag directive. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// characters into that slice. + void scanTagDirectiveHandleToSlice(const Mark startMark) @safe + { + scanTagHandleToSlice!"directive"(startMark); + enforce(reader_.peekByte() == ' ', + new ScannerException("While scanning a directive handle", startMark, + expected("' '", reader_.peek()), reader_.mark)); + } + + /// Scan prefix of a tag directive. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// characters into that slice. + void scanTagDirectivePrefixToSlice(const Mark startMark) @safe + { + scanTagURIToSlice!"directive"(startMark); + enforce(reader_.peek().among!(' ', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029'), + new ScannerException("While scanning a directive prefix", startMark, + expected("' '", reader_.peek()), reader_.mark)); + } + + /// Scan (and ignore) ignored line after a directive. + void scanDirectiveIgnoredLine(const Mark startMark) @safe + { + findNextNonSpace(); + if(reader_.peekByte() == '#') { scanToNextBreak(); } + enforce(reader_.peek().isBreak, + new ScannerException("While scanning a directive", startMark, + expected("comment or a line break", reader_.peek()), reader_.mark)); + scanLineBreak(); + } + + + /// Scan an alias or an anchor. + /// + /// The specification does not restrict characters for anchors and + /// aliases. This may lead to problems, for instance, the document: + /// [ *alias, value ] + /// can be interpteted in two ways, as + /// [ "value" ] + /// and + /// [ *alias , "value" ] + /// Therefore we restrict aliases to ASCII alphanumeric characters. + Token scanAnchor(const TokenID id) @safe + { + const startMark = reader_.mark; + const dchar i = reader_.get(); + + reader_.sliceBuilder.begin(); + if(i == '*') { scanAlphaNumericToSlice!"an alias"(startMark); } + else { scanAlphaNumericToSlice!"an anchor"(startMark); } + // On error, value is discarded as we return immediately + char[] value = reader_.sliceBuilder.finish(); + + enum anchorCtx = "While scanning an anchor"; + enum aliasCtx = "While scanning an alias"; + enforce(reader_.peek().isWhiteSpace || + reader_.peekByte().among!('?', ':', ',', ']', '}', '%', '@'), + new ScannerException(i == '*' ? aliasCtx : anchorCtx, startMark, + expected("alphanumeric, '-' or '_'", reader_.peek()), reader_.mark)); + + if(id == TokenID.alias_) + { + return aliasToken(startMark, reader_.mark, value); + } + if(id == TokenID.anchor) + { + return anchorToken(startMark, reader_.mark, value); + } + assert(false, "This code should never be reached"); + } + + /// Scan a tag token. + Token scanTag() @safe + { + const startMark = reader_.mark; + dchar c = reader_.peek(1); + + reader_.sliceBuilder.begin(); + scope(failure) { reader_.sliceBuilder.finish(); } + // Index where tag handle ends and tag suffix starts in the tag value + // (slice) we will produce. + uint handleEnd; + + if(c == '<') + { + reader_.forward(2); + + handleEnd = 0; + scanTagURIToSlice!"tag"(startMark); + enforce(reader_.peekByte() == '>', + new ScannerException("While scanning a tag", startMark, + expected("'>'", reader_.peek()), reader_.mark)); + reader_.forward(); + } + else if(c.isWhiteSpace) + { + reader_.forward(); + handleEnd = 0; + reader_.sliceBuilder.write('!'); + } + else + { + uint length = 1; + bool useHandle; + + while(!c.isBreakOrSpace) + { + if(c == '!') + { + useHandle = true; + break; + } + ++length; + c = reader_.peek(length); + } + + if(useHandle) + { + scanTagHandleToSlice!"tag"(startMark); + handleEnd = cast(uint)reader_.sliceBuilder.length; + } + else + { + reader_.forward(); + reader_.sliceBuilder.write('!'); + handleEnd = cast(uint)reader_.sliceBuilder.length; + } + + scanTagURIToSlice!"tag"(startMark); + } + + enforce(reader_.peek().isBreakOrSpace, + new ScannerException("While scanning a tag", startMark, expected("' '", reader_.peek()), + reader_.mark)); + + char[] slice = reader_.sliceBuilder.finish(); + return tagToken(startMark, reader_.mark, slice, handleEnd); + } + + /// Scan a block scalar token with specified style. + Token scanBlockScalar(const ScalarStyle style) @safe + { + const startMark = reader_.mark; + + // Scan the header. + reader_.forward(); + + const indicators = scanBlockScalarIndicators(startMark); + + const chomping = indicators[0]; + const increment = indicators[1]; + scanBlockScalarIgnoredLine(startMark); + + // Determine the indentation level and go to the first non-empty line. + Mark endMark; + uint indent = max(1, indent_ + 1); + + reader_.sliceBuilder.begin(); + alias Transaction = SliceBuilder.Transaction; + // Used to strip the last line breaks written to the slice at the end of the + // scalar, which may be needed based on chomping. + Transaction breaksTransaction = Transaction(&reader_.sliceBuilder); + // Read the first indentation/line breaks before the scalar. + size_t startLen = reader_.sliceBuilder.length; + if(increment == int.min) + { + auto indentation = scanBlockScalarIndentationToSlice(); + endMark = indentation[1]; + indent = max(indent, indentation[0]); + } + else + { + indent += increment - 1; + endMark = scanBlockScalarBreaksToSlice(indent); + } + + // int.max means there's no line break (int.max is outside UTF-32). + dchar lineBreak = cast(dchar)int.max; + + // Scan the inner part of the block scalar. + while(reader_.column == indent && reader_.peekByte() != '\0') + { + breaksTransaction.commit(); + const bool leadingNonSpace = !reader_.peekByte().among!(' ', '\t'); + // This is where the 'interesting' non-whitespace data gets read. + scanToNextBreakToSlice(); + lineBreak = scanLineBreak(); + + + // This transaction serves to rollback data read in the + // scanBlockScalarBreaksToSlice() call. + breaksTransaction = Transaction(&reader_.sliceBuilder); + startLen = reader_.sliceBuilder.length; + // The line breaks should actually be written _after_ the if() block + // below. We work around that by inserting + endMark = scanBlockScalarBreaksToSlice(indent); + + // This will not run during the last iteration (see the if() vs the + // while()), hence breaksTransaction rollback (which happens after this + // loop) will never roll back data written in this if() block. + if(reader_.column == indent && reader_.peekByte() != '\0') + { + // Unfortunately, folding rules are ambiguous. + + // This is the folding according to the specification: + if(style == ScalarStyle.folded && lineBreak == '\n' && + leadingNonSpace && !reader_.peekByte().among!(' ', '\t')) + { + // No breaks were scanned; no need to insert the space in the + // middle of slice. + if(startLen == reader_.sliceBuilder.length) + { + reader_.sliceBuilder.write(' '); + } + } + else + { + // We need to insert in the middle of the slice in case any line + // breaks were scanned. + reader_.sliceBuilder.insert(lineBreak, startLen); + } + + ////this is Clark Evans's interpretation (also in the spec + ////examples): + // + //if(style == ScalarStyle.folded && lineBreak == '\n') + //{ + // if(startLen == endLen) + // { + // if(!" \t"d.canFind(reader_.peekByte())) + // { + // reader_.sliceBuilder.write(' '); + // } + // else + // { + // chunks ~= lineBreak; + // } + // } + //} + //else + //{ + // reader_.sliceBuilder.insertBack(lineBreak, endLen - startLen); + //} + } + else + { + break; + } + } + + // If chompint is Keep, we keep (commit) the last scanned line breaks + // (which are at the end of the scalar). Otherwise re remove them (end the + // transaction). + if(chomping == Chomping.keep) { breaksTransaction.commit(); } + else { breaksTransaction.end(); } + if(chomping != Chomping.strip && lineBreak != int.max) + { + // If chomping is Keep, we keep the line break but the first line break + // that isn't stripped (since chomping isn't Strip in this branch) must + // be inserted _before_ the other line breaks. + if(chomping == Chomping.keep) + { + reader_.sliceBuilder.insert(lineBreak, startLen); + } + // If chomping is not Keep, breaksTransaction was cancelled so we can + // directly write the first line break (as it isn't stripped - chomping + // is not Strip) + else + { + reader_.sliceBuilder.write(lineBreak); + } + } + + char[] slice = reader_.sliceBuilder.finish(); + return scalarToken(startMark, endMark, slice, style); + } + + /// Scan chomping and indentation indicators of a scalar token. + Tuple!(Chomping, int) scanBlockScalarIndicators(const Mark startMark) @safe + { + auto chomping = Chomping.clip; + int increment = int.min; + dchar c = reader_.peek(); + + /// Indicators can be in any order. + if(getChomping(c, chomping)) + { + getIncrement(c, increment, startMark); + } + else + { + const gotIncrement = getIncrement(c, increment, startMark); + if(gotIncrement) { getChomping(c, chomping); } + } + + enforce(c.among!(' ', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029'), + new ScannerException("While scanning a block scalar", startMark, + expected("chomping or indentation indicator", c), reader_.mark)); + + return tuple(chomping, increment); + } + + /// Get chomping indicator, if detected. Return false otherwise. + /// + /// Used in scanBlockScalarIndicators. + /// + /// Params: + /// + /// c = The character that may be a chomping indicator. + /// chomping = Write the chomping value here, if detected. + bool getChomping(ref dchar c, ref Chomping chomping) @safe + { + if(!c.among!('+', '-')) { return false; } + chomping = c == '+' ? Chomping.keep : Chomping.strip; + reader_.forward(); + c = reader_.peek(); + return true; + } + + /// Get increment indicator, if detected. Return false otherwise. + /// + /// Used in scanBlockScalarIndicators. + /// + /// Params: + /// + /// c = The character that may be an increment indicator. + /// If an increment indicator is detected, this will be updated to + /// the next character in the Reader. + /// increment = Write the increment value here, if detected. + /// startMark = Mark for error messages. + bool getIncrement(ref dchar c, ref int increment, const Mark startMark) @safe + { + if(!c.isDigit) { return false; } + // Convert a digit to integer. + increment = c - '0'; + assert(increment < 10 && increment >= 0, "Digit has invalid value"); + + enforce(increment > 0, + new ScannerException("While scanning a block scalar", startMark, + expected("indentation indicator in range 1-9", "0"), reader_.mark)); + + reader_.forward(); + c = reader_.peek(); + return true; + } + + /// Scan (and ignore) ignored line in a block scalar. + void scanBlockScalarIgnoredLine(const Mark startMark) @safe + { + findNextNonSpace(); + if(reader_.peekByte()== '#') { scanToNextBreak(); } + + enforce(reader_.peek().isBreak, + new ScannerException("While scanning a block scalar", startMark, + expected("comment or line break", reader_.peek()), reader_.mark)); + + scanLineBreak(); + } + + /// Scan indentation in a block scalar, returning line breaks, max indent and end mark. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// characters into that slice. + Tuple!(uint, Mark) scanBlockScalarIndentationToSlice() @safe + { + uint maxIndent; + Mark endMark = reader_.mark; + + while(reader_.peek().among!(' ', '\n', '\r', '\u0085', '\u2028', '\u2029')) + { + if(reader_.peekByte() != ' ') + { + reader_.sliceBuilder.write(scanLineBreak()); + endMark = reader_.mark; + continue; + } + reader_.forward(); + maxIndent = max(reader_.column, maxIndent); + } + + return tuple(maxIndent, endMark); + } + + /// Scan line breaks at lower or specified indentation in a block scalar. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// characters into that slice. + Mark scanBlockScalarBreaksToSlice(const uint indent) @safe + { + Mark endMark = reader_.mark; + + for(;;) + { + while(reader_.column < indent && reader_.peekByte() == ' ') { reader_.forward(); } + if(!reader_.peek().among!('\n', '\r', '\u0085', '\u2028', '\u2029')) { break; } + reader_.sliceBuilder.write(scanLineBreak()); + endMark = reader_.mark; + } + + return endMark; + } + + /// Scan a qouted flow scalar token with specified quotes. + Token scanFlowScalar(const ScalarStyle quotes) @safe + { + const startMark = reader_.mark; + const quote = reader_.get(); + + reader_.sliceBuilder.begin(); + + scanFlowScalarNonSpacesToSlice(quotes, startMark); + + while(reader_.peek() != quote) + { + scanFlowScalarSpacesToSlice(startMark); + scanFlowScalarNonSpacesToSlice(quotes, startMark); + } + reader_.forward(); + + auto slice = reader_.sliceBuilder.finish(); + return scalarToken(startMark, reader_.mark, slice, quotes); + } + + /// Scan nonspace characters in a flow scalar. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// characters into that slice. + void scanFlowScalarNonSpacesToSlice(const ScalarStyle quotes, const Mark startMark) + @safe + { + for(;;) + { + dchar c = reader_.peek(); + + size_t numCodePoints; + while(!reader_.peek(numCodePoints).isFlowScalarBreakSpace) { ++numCodePoints; } + + if (numCodePoints > 0) { reader_.sliceBuilder.write(reader_.get(numCodePoints)); } + + c = reader_.peek(); + if(quotes == ScalarStyle.singleQuoted && c == '\'' && reader_.peek(1) == '\'') + { + reader_.forward(2); + reader_.sliceBuilder.write('\''); + } + else if((quotes == ScalarStyle.doubleQuoted && c == '\'') || + (quotes == ScalarStyle.singleQuoted && c.among!('"', '\\'))) + { + reader_.forward(); + reader_.sliceBuilder.write(c); + } + else if(quotes == ScalarStyle.doubleQuoted && c == '\\') + { + reader_.forward(); + c = reader_.peek(); + if(c.among!(escapes)) + { + reader_.forward(); + // Escaping has been moved to Parser as it can't be done in + // place (in a slice) in case of '\P' and '\L' (very uncommon, + // but we don't want to break the spec) + char[2] escapeSequence = ['\\', cast(char)c]; + reader_.sliceBuilder.write(escapeSequence); + } + else if(c.among!(escapeHexCodeList)) + { + const hexLength = dyaml.escapes.escapeHexLength(c); + reader_.forward(); + + foreach(i; 0 .. hexLength) { + enforce(reader_.peek(i).isHexDigit, + new ScannerException("While scanning a double quoted scalar", startMark, + expected("escape sequence of hexadecimal numbers", + reader_.peek(i)), reader_.mark)); + } + char[] hex = reader_.get(hexLength); + + enforce((hex.length > 0) && (hex.length <= 8), + new ScannerException("While scanning a double quoted scalar", startMark, + "overflow when parsing an escape sequence of " ~ + "hexadecimal numbers.", reader_.mark)); + + char[2] escapeStart = ['\\', cast(char) c]; + reader_.sliceBuilder.write(escapeStart); + reader_.sliceBuilder.write(hex); + + } + else if(c.among!('\n', '\r', '\u0085', '\u2028', '\u2029')) + { + scanLineBreak(); + scanFlowScalarBreaksToSlice(startMark); + } + else + { + throw new ScannerException("While scanning a double quoted scalar", startMark, + text("found unsupported escape character ", c), + reader_.mark); + } + } + else { return; } + } + } + + /// Scan space characters in a flow scalar. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// spaces into that slice. + void scanFlowScalarSpacesToSlice(const Mark startMark) @safe + { + // Increase length as long as we see whitespace. + size_t length; + while(reader_.peekByte(length).among!(' ', '\t')) { ++length; } + auto whitespaces = reader_.prefixBytes(length); + + // Can check the last byte without striding because '\0' is ASCII + const c = reader_.peek(length); + enforce(c != '\0', + new ScannerException("While scanning a quoted scalar", startMark, + "found unexpected end of buffer", reader_.mark)); + + // Spaces not followed by a line break. + if(!c.among!('\n', '\r', '\u0085', '\u2028', '\u2029')) + { + reader_.forward(length); + reader_.sliceBuilder.write(whitespaces); + return; + } + + // There's a line break after the spaces. + reader_.forward(length); + const lineBreak = scanLineBreak(); + + if(lineBreak != '\n') { reader_.sliceBuilder.write(lineBreak); } + + // If we have extra line breaks after the first, scan them into the + // slice. + const bool extraBreaks = scanFlowScalarBreaksToSlice(startMark); + + // No extra breaks, one normal line break. Replace it with a space. + if(lineBreak == '\n' && !extraBreaks) { reader_.sliceBuilder.write(' '); } + } + + /// Scan line breaks in a flow scalar. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// line breaks into that slice. + bool scanFlowScalarBreaksToSlice(const Mark startMark) @safe + { + // True if at least one line break was found. + bool anyBreaks; + for(;;) + { + // Instead of checking indentation, we check for document separators. + const prefix = reader_.prefix(3); + enforce(!(prefix == "---" || prefix == "...") || + !reader_.peek(3).isWhiteSpace, + new ScannerException("While scanning a quoted scalar", startMark, + "found unexpected document separator", reader_.mark)); + + // Skip any whitespaces. + while(reader_.peekByte().among!(' ', '\t')) { reader_.forward(); } + + // Encountered a non-whitespace non-linebreak character, so we're done. + if(!reader_.peek().among!(' ', '\n', '\r', '\u0085', '\u2028', '\u2029')) { break; } + + const lineBreak = scanLineBreak(); + anyBreaks = true; + reader_.sliceBuilder.write(lineBreak); + } + return anyBreaks; + } + + /// Scan plain scalar token (no block, no quotes). + Token scanPlain() @safe + { + // We keep track of the allowSimpleKey_ flag here. + // Indentation rules are loosed for the flow context + const startMark = reader_.mark; + Mark endMark = startMark; + const indent = indent_ + 1; + + // We allow zero indentation for scalars, but then we need to check for + // document separators at the beginning of the line. + // if(indent == 0) { indent = 1; } + + reader_.sliceBuilder.begin(); + + alias Transaction = SliceBuilder.Transaction; + Transaction spacesTransaction; + // Stop at a comment. + while(reader_.peekByte() != '#') + { + // Scan the entire plain scalar. + size_t length; + dchar c = reader_.peek(length); + for(;;) + { + const cNext = reader_.peek(length + 1); + if(c.isWhiteSpace || + (flowLevel_ == 0 && c == ':' && cNext.isWhiteSpace) || + (flowLevel_ > 0 && c.among!(',', ':', '?', '[', ']', '{', '}'))) + { + break; + } + ++length; + c = cNext; + } + + // It's not clear what we should do with ':' in the flow context. + enforce(flowLevel_ == 0 || c != ':' || + reader_.peek(length + 1).isWhiteSpace || + reader_.peek(length + 1).among!(',', '[', ']', '{', '}'), + new ScannerException("While scanning a plain scalar", startMark, + "found unexpected ':' . Please check " ~ + "http://pyyaml.org/wiki/YAMLColonInFlowContext for details.", + reader_.mark)); + + if(length == 0) { break; } + + allowSimpleKey_ = false; + + reader_.sliceBuilder.write(reader_.get(length)); + + endMark = reader_.mark; + + spacesTransaction.commit(); + spacesTransaction = Transaction(&reader_.sliceBuilder); + + const startLength = reader_.sliceBuilder.length; + scanPlainSpacesToSlice(); + if(startLength == reader_.sliceBuilder.length || + (flowLevel_ == 0 && reader_.column < indent)) + { + break; + } + } + + spacesTransaction.end(); + char[] slice = reader_.sliceBuilder.finish(); + + return scalarToken(startMark, endMark, slice, ScalarStyle.plain); + } + + /// Scan spaces in a plain scalar. + /// + /// Assumes that the caller is building a slice in Reader, and puts the spaces + /// into that slice. + void scanPlainSpacesToSlice() @safe + { + // The specification is really confusing about tabs in plain scalars. + // We just forbid them completely. Do not use tabs in YAML! + + // Get as many plain spaces as there are. + size_t length; + while(reader_.peekByte(length) == ' ') { ++length; } + char[] whitespaces = reader_.prefixBytes(length); + reader_.forward(length); + + const dchar c = reader_.peek(); + if(!c.isNSChar) + { + // We have spaces, but no newline. + if(whitespaces.length > 0) { reader_.sliceBuilder.write(whitespaces); } + return; + } + + // Newline after the spaces (if any) + const lineBreak = scanLineBreak(); + allowSimpleKey_ = true; + + static bool end(Reader reader_) @safe pure + { + const prefix = reader_.prefix(3); + return ("---" == prefix || "..." == prefix) + && reader_.peek(3).among!(' ', '\t', '\0', '\n', '\r', '\u0085', '\u2028', '\u2029'); + } + + if(end(reader_)) { return; } + + bool extraBreaks; + + alias Transaction = SliceBuilder.Transaction; + auto transaction = Transaction(&reader_.sliceBuilder); + if(lineBreak != '\n') { reader_.sliceBuilder.write(lineBreak); } + while(reader_.peek().isNSChar) + { + if(reader_.peekByte() == ' ') { reader_.forward(); } + else + { + const lBreak = scanLineBreak(); + extraBreaks = true; + reader_.sliceBuilder.write(lBreak); + + if(end(reader_)) { return; } + } + } + transaction.commit(); + + // No line breaks, only a space. + if(lineBreak == '\n' && !extraBreaks) { reader_.sliceBuilder.write(' '); } + } + + /// Scan handle of a tag token. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// characters into that slice. + void scanTagHandleToSlice(string name)(const Mark startMark) + { + dchar c = reader_.peek(); + enum contextMsg = "While scanning a " ~ name; + enforce(c == '!', + new ScannerException(contextMsg, startMark, expected("'!'", c), reader_.mark)); + + uint length = 1; + c = reader_.peek(length); + if(c != ' ') + { + while(c.isAlphaNum || c.among!('-', '_')) + { + ++length; + c = reader_.peek(length); + } + enforce(c == '!', + new ScannerException(contextMsg, startMark, expected("'!'", c), reader_.mark)); + ++length; + } + + reader_.sliceBuilder.write(reader_.get(length)); + } + + /// Scan URI in a tag token. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// characters into that slice. + void scanTagURIToSlice(string name)(const Mark startMark) + { + // Note: we do not check if URI is well-formed. + dchar c = reader_.peek(); + const startLen = reader_.sliceBuilder.length; + { + uint length; + while(c.isAlphaNum || c.isURIChar) + { + if(c == '%') + { + auto chars = reader_.get(length); + reader_.sliceBuilder.write(chars); + length = 0; + scanURIEscapesToSlice!name(startMark); + } + else { ++length; } + c = reader_.peek(length); + } + if(length > 0) + { + auto chars = reader_.get(length); + reader_.sliceBuilder.write(chars); + length = 0; + } + } + // OK if we scanned something, error otherwise. + enum contextMsg = "While parsing a " ~ name; + enforce(reader_.sliceBuilder.length > startLen, + new ScannerException(contextMsg, startMark, expected("URI", c), reader_.mark)); + } + + // Not @nogc yet because std.utf.decode is not @nogc + /// Scan URI escape sequences. + /// + /// Assumes that the caller is building a slice in Reader, and puts the scanned + /// characters into that slice. + void scanURIEscapesToSlice(string name)(const Mark startMark) + { + import core.exception : UnicodeException; + // URI escapes encode a UTF-8 string. We store UTF-8 code units here for + // decoding into UTF-32. + Appender!string buffer; + + + enum contextMsg = "While scanning a " ~ name; + while(reader_.peekByte() == '%') + { + reader_.forward(); + char[2] nextByte = [reader_.peekByte(), reader_.peekByte(1)]; + + enforce(nextByte[0].isHexDigit && nextByte[1].isHexDigit, + new ScannerException(contextMsg, startMark, + expected("URI escape sequence of 2 hexadecimal " ~ + "numbers", nextByte), reader_.mark)); + + buffer ~= nextByte[].to!ubyte(16); + + reader_.forward(2); + } + try + { + foreach (dchar chr; buffer.data) + { + reader_.sliceBuilder.write(chr); + } + } + catch (UnicodeException) + { + throw new ScannerException(contextMsg, startMark, + "Invalid UTF-8 data encoded in URI escape sequence", + reader_.mark); + } + } + + + /// Scan a line break, if any. + /// + /// Transforms: + /// '\r\n' : '\n' + /// '\r' : '\n' + /// '\n' : '\n' + /// '\u0085' : '\n' + /// '\u2028' : '\u2028' + /// '\u2029 : '\u2029' + /// no break : '\0' + dchar scanLineBreak() @safe + { + // Fast path for ASCII line breaks. + const b = reader_.peekByte(); + if(b < 0x80) + { + if(b == '\n' || b == '\r') + { + if(reader_.prefix(2) == "\r\n") { reader_.forward(2); } + else { reader_.forward(); } + return '\n'; + } + return '\0'; + } + + const c = reader_.peek(); + if(c == '\x85') + { + reader_.forward(); + return '\n'; + } + if(c == '\u2028' || c == '\u2029') + { + reader_.forward(); + return c; + } + return '\0'; + } +} diff --git a/src/ext_depends/D-YAML/source/dyaml/serializer.d b/src/ext_depends/D-YAML/source/dyaml/serializer.d new file mode 100644 index 0000000..4100cf3 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/serializer.d @@ -0,0 +1,322 @@ + +// 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) + +/** + * YAML serializer. + * Code based on PyYAML: http://www.pyyaml.org + */ +module dyaml.serializer; + + +import std.array; +import std.format; +import std.typecons; + +import dyaml.emitter; +import dyaml.event; +import dyaml.exception; +import dyaml.node; +import dyaml.resolver; +import dyaml.tagdirective; +import dyaml.token; + + +package: + +///Serializes represented YAML nodes, generating events which are then emitted by Emitter. +struct Serializer +{ + private: + ///Resolver used to determine which tags are automaticaly resolvable. + Resolver resolver_; + + ///Do all document starts have to be specified explicitly? + Flag!"explicitStart" explicitStart_; + ///Do all document ends have to be specified explicitly? + Flag!"explicitEnd" explicitEnd_; + ///YAML version string. + string YAMLVersion_; + + ///Tag directives to emit. + TagDirective[] tagDirectives_; + + //TODO Use something with more deterministic memory usage. + ///Nodes with assigned anchors. + string[Node] anchors_; + ///Nodes with assigned anchors that are already serialized. + bool[Node] serializedNodes_; + ///ID of the last anchor generated. + uint lastAnchorID_ = 0; + + public: + /** + * Construct a Serializer. + * + * Params: + * resolver = Resolver used to determine which tags are automaticaly resolvable. + * explicitStart = Do all document starts have to be specified explicitly? + * explicitEnd = Do all document ends have to be specified explicitly? + * YAMLVersion = YAML version string. + * tagDirectives = Tag directives to emit. + */ + this(Resolver resolver, + const Flag!"explicitStart" explicitStart, + const Flag!"explicitEnd" explicitEnd, string YAMLVersion, + TagDirective[] tagDirectives) @safe + { + resolver_ = resolver; + explicitStart_ = explicitStart; + explicitEnd_ = explicitEnd; + YAMLVersion_ = YAMLVersion; + tagDirectives_ = tagDirectives; + } + + ///Begin the stream. + void startStream(EmitterT)(ref EmitterT emitter) @safe + { + emitter.emit(streamStartEvent(Mark(), Mark())); + } + + ///End the stream. + void endStream(EmitterT)(ref EmitterT emitter) @safe + { + emitter.emit(streamEndEvent(Mark(), Mark())); + } + + ///Serialize a node, emitting it in the process. + void serialize(EmitterT)(ref EmitterT emitter, ref Node node) @safe + { + emitter.emit(documentStartEvent(Mark(), Mark(), explicitStart_, + YAMLVersion_, tagDirectives_)); + anchorNode(node); + serializeNode(emitter, node); + emitter.emit(documentEndEvent(Mark(), Mark(), explicitEnd_)); + serializedNodes_.destroy(); + anchors_.destroy(); + string[Node] emptyAnchors; + anchors_ = emptyAnchors; + lastAnchorID_ = 0; + } + + private: + /** + * Determine if it's a good idea to add an anchor to a node. + * + * Used to prevent associating every single repeating scalar with an + * anchor/alias - only nodes long enough can use anchors. + * + * Params: node = Node to check for anchorability. + * + * Returns: True if the node is anchorable, false otherwise. + */ + static bool anchorable(ref Node node) @safe + { + if(node.nodeID == NodeID.scalar) + { + return (node.type == NodeType.string) ? node.as!string.length > 64 : + (node.type == NodeType.binary) ? node.as!(ubyte[]).length > 64 : + false; + } + return node.length > 2; + } + + @safe unittest + { + import std.string : representation; + auto shortString = "not much"; + auto longString = "A fairly long string that would be a good idea to add an anchor to"; + auto node1 = Node(shortString); + auto node2 = Node(shortString.representation.dup); + auto node3 = Node(longString); + auto node4 = Node(longString.representation.dup); + auto node5 = Node([node1]); + auto node6 = Node([node1, node2, node3, node4]); + assert(!anchorable(node1)); + assert(!anchorable(node2)); + assert(anchorable(node3)); + assert(anchorable(node4)); + assert(!anchorable(node5)); + assert(anchorable(node6)); + } + + ///Add an anchor to the node if it's anchorable and not anchored yet. + void anchorNode(ref Node node) @safe + { + if(!anchorable(node)){return;} + + if((node in anchors_) !is null) + { + if(anchors_[node] is null) + { + anchors_[node] = generateAnchor(); + } + return; + } + + anchors_.remove(node); + final switch (node.nodeID) + { + case NodeID.mapping: + foreach(ref Node key, ref Node value; node) + { + anchorNode(key); + anchorNode(value); + } + break; + case NodeID.sequence: + foreach(ref Node item; node) + { + anchorNode(item); + } + break; + case NodeID.invalid: + assert(0); + case NodeID.scalar: + } + } + + ///Generate and return a new anchor. + string generateAnchor() @safe + { + ++lastAnchorID_; + auto appender = appender!string(); + formattedWrite(appender, "id%03d", lastAnchorID_); + return appender.data; + } + + ///Serialize a node and all its subnodes. + void serializeNode(EmitterT)(ref EmitterT emitter, ref Node node) @safe + { + //If the node has an anchor, emit an anchor (as aliasEvent) on the + //first occurrence, save it in serializedNodes_, and emit an alias + //if it reappears. + string aliased; + if(anchorable(node) && (node in anchors_) !is null) + { + aliased = anchors_[node]; + if((node in serializedNodes_) !is null) + { + emitter.emit(aliasEvent(Mark(), Mark(), aliased)); + return; + } + serializedNodes_[node] = true; + } + final switch (node.nodeID) + { + case NodeID.mapping: + const defaultTag = resolver_.defaultMappingTag; + const implicit = node.tag_ == defaultTag; + emitter.emit(mappingStartEvent(Mark(), Mark(), aliased, node.tag_, + implicit, node.collectionStyle)); + foreach(ref Node key, ref Node value; node) + { + serializeNode(emitter, key); + serializeNode(emitter, value); + } + emitter.emit(mappingEndEvent(Mark(), Mark())); + return; + case NodeID.sequence: + const defaultTag = resolver_.defaultSequenceTag; + const implicit = node.tag_ == defaultTag; + emitter.emit(sequenceStartEvent(Mark(), Mark(), aliased, node.tag_, + implicit, node.collectionStyle)); + foreach(ref Node item; node) + { + serializeNode(emitter, item); + } + emitter.emit(sequenceEndEvent(Mark(), Mark())); + return; + case NodeID.scalar: + assert(node.type == NodeType.string, "Scalar node type must be string before serialized"); + auto value = node.as!string; + const detectedTag = resolver_.resolve(NodeID.scalar, null, value, true); + const bool isDetected = node.tag_ == detectedTag; + + emitter.emit(scalarEvent(Mark(), Mark(), aliased, node.tag_, + isDetected, value, node.scalarStyle)); + return; + case NodeID.invalid: + assert(0); + } + } +} + +// Issue #244 +@safe unittest +{ + import dyaml.dumper : dumper; + auto node = Node([ + Node.Pair( + Node(""), + Node([ + Node([ + Node.Pair( + Node("d"), + Node([ + Node([ + Node.Pair( + Node("c"), + Node("") + ), + Node.Pair( + Node("b"), + Node("") + ), + Node.Pair( + Node(""), + Node("") + ) + ]) + ]) + ), + ]), + Node([ + Node.Pair( + Node("d"), + Node([ + Node(""), + Node(""), + Node([ + Node.Pair( + Node("c"), + Node("") + ), + Node.Pair( + Node("b"), + Node("") + ), + Node.Pair( + Node(""), + Node("") + ) + ]) + ]) + ), + Node.Pair( + Node("z"), + Node("") + ), + Node.Pair( + Node(""), + Node("") + ) + ]), + Node("") + ]) + ), + Node.Pair( + Node("g"), + Node("") + ), + Node.Pair( + Node("h"), + Node("") + ), + ]); + + auto stream = appender!string(); + dumper().dump(stream, node); +} diff --git a/src/ext_depends/D-YAML/source/dyaml/style.d b/src/ext_depends/D-YAML/source/dyaml/style.d new file mode 100644 index 0000000..319592c --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/style.d @@ -0,0 +1,37 @@ + +// 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) + +///YAML node formatting styles. +module dyaml.style; + + +///Scalar styles. +enum ScalarStyle : ubyte +{ + /// Invalid (uninitialized) style + invalid = 0, + /// `|` (Literal block style) + literal, + /// `>` (Folded block style) + folded, + /// Plain scalar + plain, + /// Single quoted scalar + singleQuoted, + /// Double quoted scalar + doubleQuoted +} + +///Collection styles. +enum CollectionStyle : ubyte +{ + /// Invalid (uninitialized) style + invalid = 0, + /// Block style. + block, + /// Flow style. + flow +} diff --git a/src/ext_depends/D-YAML/source/dyaml/tagdirective.d b/src/ext_depends/D-YAML/source/dyaml/tagdirective.d new file mode 100644 index 0000000..54687fe --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/tagdirective.d @@ -0,0 +1,15 @@ + +// 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) + +///Tag directives. +module dyaml.tagdirective; + +///Single tag directive. handle is the shortcut, prefix is the prefix that replaces it. +struct TagDirective +{ + string handle; + string prefix; +} diff --git a/src/ext_depends/D-YAML/source/dyaml/test/common.d b/src/ext_depends/D-YAML/source/dyaml/test/common.d new file mode 100644 index 0000000..a6bafa9 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/test/common.d @@ -0,0 +1,223 @@ + +// 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) + +module dyaml.test.common; + +version(unittest) +{ + +import dyaml.node; +import dyaml.event; + +import core.exception; +import std.algorithm; +import std.array; +import std.conv; +import std.file; +import std.range; +import std.path; +import std.traits; +import std.typecons; + +package: + +/** +Run a test. + +Params: + testFunction = Unittest function. + unittestExt = Extensions of data files needed for the unittest. + skipExt = Extensions that must not be used for the unittest. + */ +void run(D)(D testFunction, string[] unittestExt, string[] skipExt = []) +{ + immutable string dataDir = __FILE_FULL_PATH__.dirName ~ "/../../../test/data"; + auto testFilenames = findTestFilenames(dataDir); + + if (unittestExt.length > 0) + { + outer: foreach (base, extensions; testFilenames) + { + string[] filenames; + foreach (ext; unittestExt) + { + if (!extensions.canFind(ext)) + { + continue outer; + } + filenames ~= base ~ '.' ~ ext; + } + foreach (ext; skipExt) + { + if (extensions.canFind(ext)) + { + continue outer; + } + } + + execute(testFunction, filenames); + } + } + else + { + execute(testFunction, string[].init); + } +} + +// TODO: remove when a @safe ubyte[] file read can be done. +/** +Reads a file as an array of bytes. + +Params: + filename = Full path to file to read. + +Returns: The file's data. +*/ +ubyte[] readData(string filename) @trusted +{ + import std.file : read; + return cast(ubyte[])read(filename); +} +void assertNodesEqual(const scope Node gotNode, const scope Node expectedNode) @safe +{ + import std.format : format; + assert(gotNode == expectedNode, format!"got %s, expected %s"(gotNode.debugString, expectedNode.debugString)); +} + +/** +Determine if events in events1 are equivalent to events in events2. + +Params: + events1 = A range of events to compare with. + events2 = A second range of events to compare. + +Returns: true if the events are equivalent, false otherwise. +*/ +bool compareEvents(T, U)(T events1, U events2) +if (isInputRange!T && isInputRange!U && is(ElementType!T == Event) && is(ElementType!U == Event)) +{ + foreach (e1, e2; zip(events1, events2)) + { + //Different event types. + if (e1.id != e2.id) + { + return false; + } + //Different anchor (if applicable). + if (e1.id.among!(EventID.sequenceStart, EventID.mappingStart, EventID.alias_, EventID.scalar) + && e1.anchor != e2.anchor) + { + return false; + } + //Different collection tag (if applicable). + if (e1.id.among!(EventID.sequenceStart, EventID.mappingStart) && e1.tag != e2.tag) + { + return false; + } + if (e1.id == EventID.scalar) + { + //Different scalar tag (if applicable). + if (!(e1.implicit || e2.implicit) && e1.tag != e2.tag) + { + return false; + } + //Different scalar value. + if (e1.value != e2.value) + { + return false; + } + } + } + return true; +} +/** +Throw an Error if events in events1 aren't equivalent to events in events2. + +Params: + events1 = First event array to compare. + events2 = Second event array to compare. +*/ +void assertEventsEqual(T, U)(T events1, U events2) +if (isInputRange!T && isInputRange!U && is(ElementType!T == Event) && is(ElementType!U == Event)) +{ + auto events1Copy = events1.array; + auto events2Copy = events2.array; + assert(compareEvents(events1Copy, events2Copy), text("Got '", events1Copy, "', expected '", events2Copy, "'")); +} + +private: + +/** +Find unittest input filenames. + +Params: dir = Directory to look in. + +Returns: Test input base filenames and their extensions. +*/ + //@trusted due to dirEntries +string[][string] findTestFilenames(const string dir) @trusted +{ + //Groups of extensions indexed by base names. + string[][string] names; + foreach (string name; dirEntries(dir, SpanMode.shallow)) + { + if (isFile(name)) + { + string base = name.stripExtension(); + string ext = name.extension(); + if (ext is null) + { + ext = ""; + } + if (ext[0] == '.') + { + ext = ext[1 .. $]; + } + + //If the base name doesn't exist yet, add it; otherwise add new extension. + names[base] = ((base in names) is null) ? [ext] : names[base] ~ ext; + } + } + return names; +} + +/** +Recursively copy an array of strings to a tuple to use for unittest function input. + +Params: + index = Current index in the array/tuple. + tuple = Tuple to copy to. + strings = Strings to copy. +*/ +void stringsToTuple(uint index, F ...)(ref F tuple, const string[] strings) +in(F.length == strings.length) +do +{ + tuple[index] = strings[index]; + static if (index > 0) + { + stringsToTuple!(index - 1, F)(tuple, strings); + } +} + +/** +Execute an unittest on specified files. + +Params: + testName = Name of the unittest. + testFunction = Unittest function. + filenames = Names of input files to test with. + */ +void execute(D)(D testFunction, string[] filenames) +{ + //Convert filenames to parameters tuple and call the test function. + alias F = Parameters!D[0..$]; + F parameters; + stringsToTuple!(F.length - 1, F)(parameters, filenames); + testFunction(parameters); +} + +} // version(unittest) diff --git a/src/ext_depends/D-YAML/source/dyaml/test/compare.d b/src/ext_depends/D-YAML/source/dyaml/test/compare.d new file mode 100644 index 0000000..5a37fd0 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/test/compare.d @@ -0,0 +1,51 @@ + +// 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) + +module dyaml.test.compare; + +@safe unittest +{ + import dyaml : Loader; + import dyaml.test.common : assertNodesEqual, compareEvents, run; + + /** + Test parser by comparing output from parsing two equivalent YAML files. + + Params: + dataFilename = YAML file to parse. + canonicalFilename = Another file to parse, in canonical YAML format. + */ + static void testParser(string dataFilename, string canonicalFilename) @safe + { + auto dataEvents = Loader.fromFile(dataFilename).parse(); + auto canonicalEvents = Loader.fromFile(canonicalFilename).parse(); + + //BUG: the return value isn't checked! This test currently fails... + compareEvents(dataEvents, canonicalEvents); + } + + /** + Test loader by comparing output from loading two equivalent YAML files. + + Params: + dataFilename = YAML file to load. + canonicalFilename = Another file to load, in canonical YAML format. + */ + static void testLoader(string dataFilename, string canonicalFilename) @safe + { + import std.array : array; + auto data = Loader.fromFile(dataFilename).array; + auto canonical = Loader.fromFile(canonicalFilename).array; + + assert(data.length == canonical.length, "Unequal node count"); + foreach (n; 0 .. data.length) + { + assertNodesEqual(data[n], canonical[n]); + } + } + run(&testParser, ["data", "canonical"]); + run(&testLoader, ["data", "canonical"], ["test_loader_skip"]); +} diff --git a/src/ext_depends/D-YAML/source/dyaml/test/constructor.d b/src/ext_depends/D-YAML/source/dyaml/test/constructor.d new file mode 100644 index 0000000..aeb8653 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/test/constructor.d @@ -0,0 +1,957 @@ + +// 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) + +module dyaml.test.constructor; + + +version(unittest) +{ + +import std.conv; +import std.datetime; +import std.exception; +import std.path; +import std.string; +import std.typecons; + +import dyaml : Loader, Node, YAMLNull; + +///Expected results of loading test inputs. +Node[][string] expected; + +///Initialize expected. +static this() @safe +{ + expected["aliases-cdumper-bug"] = constructAliasesCDumperBug(); + expected["construct-binary"] = constructBinary(); + expected["construct-bool"] = constructBool(); + expected["construct-custom"] = constructCustom(); + expected["construct-float"] = constructFloat(); + expected["construct-int"] = constructInt(); + expected["construct-map"] = constructMap(); + expected["construct-merge"] = constructMerge(); + expected["construct-null"] = constructNull(); + expected["construct-omap"] = constructOMap(); + expected["construct-pairs"] = constructPairs(); + expected["construct-seq"] = constructSeq(); + expected["construct-set"] = constructSet(); + expected["construct-str-ascii"] = constructStrASCII(); + expected["construct-str"] = constructStr(); + expected["construct-str-utf8"] = constructStrUTF8(); + expected["construct-timestamp"] = constructTimestamp(); + expected["construct-value"] = constructValue(); + expected["duplicate-merge-key"] = duplicateMergeKey(); + expected["float-representer-2.3-bug"] = floatRepresenterBug(); + expected["invalid-single-quote-bug"] = invalidSingleQuoteBug(); + expected["more-floats"] = moreFloats(); + expected["negative-float-bug"] = negativeFloatBug(); + expected["single-dot-is-not-float-bug"] = singleDotFloatBug(); + expected["timestamp-bugs"] = timestampBugs(); + expected["utf16be"] = utf16be(); + expected["utf16le"] = utf16le(); + expected["utf8"] = utf8(); + expected["utf8-implicit"] = utf8implicit(); +} + +///Construct a pair of nodes with specified values. +Node.Pair pair(A, B)(A a, B b) +{ + return Node.Pair(a,b); +} + +///Test cases: + +Node[] constructAliasesCDumperBug() @safe +{ + return [ + Node( + [ + Node("today", "tag:yaml.org,2002:str"), + Node("today", "tag:yaml.org,2002:str") + ], + "tag:yaml.org,2002:seq") + ]; +} + +Node[] constructBinary() @safe +{ + auto canonical = "GIF89a\x0c\x00\x0c\x00\x84\x00\x00\xff\xff\xf7\xf5\xf5\xee\xe9\xe9\xe5fff\x00\x00\x00\xe7\xe7\xe7^^^\xf3\xf3\xed\x8e\x8e\x8e\xe0\xe0\xe0\x9f\x9f\x9f\x93\x93\x93\xa7\xa7\xa7\x9e\x9e\x9eiiiccc\xa3\xa3\xa3\x84\x84\x84\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9!\xfe\x0eMade with GIMP\x00,\x00\x00\x00\x00\x0c\x00\x0c\x00\x00\x05, \x8e\x810\x9e\xe3@\x14\xe8i\x10\xc4\xd1\x8a\x08\x1c\xcf\x80M$z\xef\xff0\x85p\xb8\xb01f\r\x1b\xce\x01\xc3\x01\x1e\x10' \x82\n\x01\x00;".representation.dup; + auto generic = "GIF89a\x0c\x00\x0c\x00\x84\x00\x00\xff\xff\xf7\xf5\xf5\xee\xe9\xe9\xe5fff\x00\x00\x00\xe7\xe7\xe7^^^\xf3\xf3\xed\x8e\x8e\x8e\xe0\xe0\xe0\x9f\x9f\x9f\x93\x93\x93\xa7\xa7\xa7\x9e\x9e\x9eiiiccc\xa3\xa3\xa3\x84\x84\x84\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9\xff\xfe\xf9!\xfe\x0eMade with GIMP\x00,\x00\x00\x00\x00\x0c\x00\x0c\x00\x00\x05, \x8e\x810\x9e\xe3@\x14\xe8i\x10\xc4\xd1\x8a\x08\x1c\xcf\x80M$z\xef\xff0\x85p\xb8\xb01f\r\x1b\xce\x01\xc3\x01\x1e\x10' \x82\n\x01\x00;".representation.dup; + auto description = "The binary value above is a tiny arrow encoded as a gif image."; + + return [ + Node( + [ + pair( + Node("canonical", "tag:yaml.org,2002:str"), + Node(canonical, "tag:yaml.org,2002:binary") + ), + pair( + Node("generic", "tag:yaml.org,2002:str"), + Node(generic, "tag:yaml.org,2002:binary") + ), + pair( + Node("description", "tag:yaml.org,2002:str"), + Node(description, "tag:yaml.org,2002:str") + ) + ], + "tag:yaml.org,2002:map") + ]; +} + +Node[] constructBool() @safe +{ + const(bool) a = true; + immutable(bool) b = true; + const bool aa = true; + immutable bool bb = true; + return [ + Node( + [ + pair( + Node("canonical", "tag:yaml.org,2002:str"), + Node(true, "tag:yaml.org,2002:bool") + ), + pair( + Node("answer", "tag:yaml.org,2002:str"), + Node(false, "tag:yaml.org,2002:bool") + ), + pair( + Node("logical", "tag:yaml.org,2002:str"), + Node(true, "tag:yaml.org,2002:bool") + ), + pair( + Node("option", "tag:yaml.org,2002:str"), + Node(true, "tag:yaml.org,2002:bool") + ), + pair( + Node("constbool", "tag:yaml.org,2002:str"), + Node(a, "tag:yaml.org,2002:bool") + ), + pair( + Node("imutbool", "tag:yaml.org,2002:str"), + Node(b, "tag:yaml.org,2002:bool") + ), + pair( + Node("const_bool", "tag:yaml.org,2002:str"), + Node(aa, "tag:yaml.org,2002:bool") + ), + pair( + Node("imut_bool", "tag:yaml.org,2002:str"), + Node(bb, "tag:yaml.org,2002:bool") + ), + pair( + Node("but", "tag:yaml.org,2002:str"), + Node( + [ + pair( + Node("y", "tag:yaml.org,2002:str"), + Node("is a string", "tag:yaml.org,2002:str") + ), + pair( + Node("n", "tag:yaml.org,2002:str"), + Node("is a string", "tag:yaml.org,2002:str") + ) + ], + "tag:yaml.org,2002:map") + ) + ], + "tag:yaml.org,2002:map") + ]; +} + +Node[] constructCustom() @safe +{ + return [ + Node( + [ + Node(new TestClass(1, 2, 3)), + Node(TestStruct(10)) + ], + "tag:yaml.org,2002:seq") + ]; +} + +Node[] constructFloat() @safe +{ + return [ + Node( + [ + pair( + Node("canonical", "tag:yaml.org,2002:str"), + Node(685230.15L, "tag:yaml.org,2002:float") + ), + pair( + Node("exponential", "tag:yaml.org,2002:str"), + Node(685230.15L, "tag:yaml.org,2002:float") + ), + pair( + Node("fixed", "tag:yaml.org,2002:str"), + Node(685230.15L, "tag:yaml.org,2002:float") + ), + pair( + Node("sexagesimal", "tag:yaml.org,2002:str"), + Node(685230.15L, "tag:yaml.org,2002:float") + ), + pair( + Node("negative infinity", "tag:yaml.org,2002:str"), + Node(-real.infinity, "tag:yaml.org,2002:float") + ), + pair( + Node("not a number", "tag:yaml.org,2002:str"), + Node(real.nan, "tag:yaml.org,2002:float") + ) + ], + "tag:yaml.org,2002:map") + ]; +} + +Node[] constructInt() @safe +{ + return [ + Node( + [ + pair( + Node("canonical", "tag:yaml.org,2002:str"), + Node(685230L, "tag:yaml.org,2002:int") + ), + pair( + Node("decimal", "tag:yaml.org,2002:str"), + Node(685230L, "tag:yaml.org,2002:int") + ), + pair( + Node("octal", "tag:yaml.org,2002:str"), + Node(685230L, "tag:yaml.org,2002:int") + ), + pair( + Node("hexadecimal", "tag:yaml.org,2002:str"), + Node(685230L, "tag:yaml.org,2002:int") + ), + pair( + Node("binary", "tag:yaml.org,2002:str"), + Node(685230L, "tag:yaml.org,2002:int") + ), + pair( + Node("sexagesimal", "tag:yaml.org,2002:str"), + Node(685230L, "tag:yaml.org,2002:int") + ) + ], + "tag:yaml.org,2002:map") + ]; +} + +Node[] constructMap() @safe +{ + return [ + Node( + [ + pair( + Node("Block style", "tag:yaml.org,2002:str"), + Node( + [ + pair( + Node("Clark", "tag:yaml.org,2002:str"), + Node("Evans", "tag:yaml.org,2002:str") + ), + pair( + Node("Brian", "tag:yaml.org,2002:str"), + Node("Ingerson", "tag:yaml.org,2002:str") + ), + pair( + Node("Oren", "tag:yaml.org,2002:str"), + Node("Ben-Kiki", "tag:yaml.org,2002:str") + ) + ], + "tag:yaml.org,2002:map") + ), + pair( + Node("Flow style", "tag:yaml.org,2002:str"), + Node( + [ + pair( + Node("Clark", "tag:yaml.org,2002:str"), + Node("Evans", "tag:yaml.org,2002:str") + ), + pair( + Node("Brian", "tag:yaml.org,2002:str"), + Node("Ingerson", "tag:yaml.org,2002:str") + ), + pair( + Node("Oren", "tag:yaml.org,2002:str"), + Node("Ben-Kiki", "tag:yaml.org,2002:str") + ) + ], + "tag:yaml.org,2002:map") + ) + ], + "tag:yaml.org,2002:map") + ]; +} + +Node[] constructMerge() @safe +{ + return [ + Node( + [ + Node( + [ + pair( + Node("x", "tag:yaml.org,2002:str"), + Node(1L, "tag:yaml.org,2002:int") + ), + pair( + Node("y", "tag:yaml.org,2002:str"), + Node(2L, "tag:yaml.org,2002:int") + ) + ], + "tag:yaml.org,2002:map"), + Node( + [ + pair( + Node("x", "tag:yaml.org,2002:str"), + Node(0L, "tag:yaml.org,2002:int") + ), + pair( + Node("y", "tag:yaml.org,2002:str"), + Node(2L, "tag:yaml.org,2002:int") + ) + ], + "tag:yaml.org,2002:map"), + Node( + [ + pair( + Node("r", "tag:yaml.org,2002:str"), + Node(10L, "tag:yaml.org,2002:int") + ) + ], + "tag:yaml.org,2002:map"), + Node( + [ + pair( + Node("r", "tag:yaml.org,2002:str"), + Node(1L, "tag:yaml.org,2002:int") + ) + ], + "tag:yaml.org,2002:map"), + Node( + [ + pair( + Node("x", "tag:yaml.org,2002:str"), + Node(1L, "tag:yaml.org,2002:int") + ), + pair( + Node("y", "tag:yaml.org,2002:str"), + Node(2L, "tag:yaml.org,2002:int") + ), + pair( + Node("r", "tag:yaml.org,2002:str"), + Node(10L, "tag:yaml.org,2002:int") + ), + pair( + Node("label", "tag:yaml.org,2002:str"), + Node("center/big", "tag:yaml.org,2002:str") + ) + ], + "tag:yaml.org,2002:map"), + Node( + [ + pair( + Node("r", "tag:yaml.org,2002:str"), + Node(10L, "tag:yaml.org,2002:int") + ), + pair( + Node("label", "tag:yaml.org,2002:str"), + Node("center/big", "tag:yaml.org,2002:str") + ), + pair( + Node("x", "tag:yaml.org,2002:str"), + Node(1L, "tag:yaml.org,2002:int") + ), + pair( + Node("y", "tag:yaml.org,2002:str"), + Node(2L, "tag:yaml.org,2002:int") + ) + ], + "tag:yaml.org,2002:map"), + Node( + [ + pair( + Node("label", "tag:yaml.org,2002:str"), + Node("center/big", "tag:yaml.org,2002:str") + ), + pair( + Node("x", "tag:yaml.org,2002:str"), + Node(1L, "tag:yaml.org,2002:int") + ), + pair( + Node("y", "tag:yaml.org,2002:str"), + Node(2L, "tag:yaml.org,2002:int") + ), + pair( + Node("r", "tag:yaml.org,2002:str"), + Node(10L, "tag:yaml.org,2002:int") + ) + ], + "tag:yaml.org,2002:map"), + Node( + [ + pair( + Node("x", "tag:yaml.org,2002:str"), + Node(1L, "tag:yaml.org,2002:int") + ), + pair( + Node("label", "tag:yaml.org,2002:str"), + Node("center/big", "tag:yaml.org,2002:str") + ), + pair( + Node("r", "tag:yaml.org,2002:str"), + Node(10L, "tag:yaml.org,2002:int") + ), + pair( + Node("y", "tag:yaml.org,2002:str"), + Node(2L, "tag:yaml.org,2002:int") + ) + ], + "tag:yaml.org,2002:map") + ], + "tag:yaml.org,2002:seq") + ]; +} + +Node[] constructNull() @safe +{ + return [ + Node(YAMLNull(), "tag:yaml.org,2002:null"), + Node( + [ + pair( + Node("empty", "tag:yaml.org,2002:str"), + Node(YAMLNull(), "tag:yaml.org,2002:null") + ), + pair( + Node("canonical", "tag:yaml.org,2002:str"), + Node(YAMLNull(), "tag:yaml.org,2002:null") + ), + pair( + Node("english", "tag:yaml.org,2002:str"), + Node(YAMLNull(), "tag:yaml.org,2002:null") + ), + pair( + Node(YAMLNull(), "tag:yaml.org,2002:null"), + Node("null key", "tag:yaml.org,2002:str") + ) + ], + "tag:yaml.org,2002:map"), + Node( + [ + pair( + Node("sparse", "tag:yaml.org,2002:str"), + Node( + [ + Node(YAMLNull(), "tag:yaml.org,2002:null"), + Node("2nd entry", "tag:yaml.org,2002:str"), + Node(YAMLNull(), "tag:yaml.org,2002:null"), + Node("4th entry", "tag:yaml.org,2002:str"), + Node(YAMLNull(), "tag:yaml.org,2002:null") + ], + "tag:yaml.org,2002:seq") + ) + ], + "tag:yaml.org,2002:map") + ]; +} + +Node[] constructOMap() @safe +{ + return [ + Node( + [ + pair( + Node("Bestiary", "tag:yaml.org,2002:str"), + Node( + [ + pair( + Node("aardvark", "tag:yaml.org,2002:str"), + Node("African pig-like ant eater. Ugly.", "tag:yaml.org,2002:str") + ), + pair( + Node("anteater", "tag:yaml.org,2002:str"), + Node("South-American ant eater. Two species.", "tag:yaml.org,2002:str") + ), + pair( + Node("anaconda", "tag:yaml.org,2002:str"), + Node("South-American constrictor snake. Scaly.", "tag:yaml.org,2002:str") + ) + ], + "tag:yaml.org,2002:omap") + ), + pair( + Node("Numbers", "tag:yaml.org,2002:str"), + Node( + [ + pair( + Node("one", "tag:yaml.org,2002:str"), + Node(1L, "tag:yaml.org,2002:int") + ), + pair( + Node("two", "tag:yaml.org,2002:str"), + Node(2L, "tag:yaml.org,2002:int") + ), + pair( + Node("three", "tag:yaml.org,2002:str"), + Node(3L, "tag:yaml.org,2002:int") + ) + ], + "tag:yaml.org,2002:omap") + ) + ], + "tag:yaml.org,2002:map") + ]; +} + +Node[] constructPairs() @safe +{ + return [ + Node( + [ + pair( + Node("Block tasks", "tag:yaml.org,2002:str"), + Node( + [ + pair(Node("meeting", "tag:yaml.org,2002:str"), Node("with team.", "tag:yaml.org,2002:str")), + pair(Node("meeting", "tag:yaml.org,2002:str"), Node("with boss.", "tag:yaml.org,2002:str")), + pair(Node("break", "tag:yaml.org,2002:str"), Node("lunch.", "tag:yaml.org,2002:str")), + pair(Node("meeting", "tag:yaml.org,2002:str"), Node("with client.", "tag:yaml.org,2002:str")) + ], + "tag:yaml.org,2002:pairs") + ), + pair( + Node("Flow tasks", "tag:yaml.org,2002:str"), + Node( + [ + pair(Node("meeting", "tag:yaml.org,2002:str"), Node("with team", "tag:yaml.org,2002:str")), + pair(Node("meeting", "tag:yaml.org,2002:str"), Node("with boss", "tag:yaml.org,2002:str")) + ], + "tag:yaml.org,2002:pairs") + ) + ], + "tag:yaml.org,2002:map") + ]; +} + +Node[] constructSeq() @safe +{ + return [ + Node( + [ + pair( + Node("Block style", "tag:yaml.org,2002:str"), + Node([ + Node("Mercury", "tag:yaml.org,2002:str"), + Node("Venus", "tag:yaml.org,2002:str"), + Node("Earth", "tag:yaml.org,2002:str"), + Node("Mars", "tag:yaml.org,2002:str"), + Node("Jupiter", "tag:yaml.org,2002:str"), + Node("Saturn", "tag:yaml.org,2002:str"), + Node("Uranus", "tag:yaml.org,2002:str"), + Node("Neptune", "tag:yaml.org,2002:str"), + Node("Pluto", "tag:yaml.org,2002:str") + ], "tag:yaml.org,2002:seq") + ), + pair( + Node("Flow style", "tag:yaml.org,2002:str"), + Node([ + Node("Mercury", "tag:yaml.org,2002:str"), + Node("Venus", "tag:yaml.org,2002:str"), + Node("Earth", "tag:yaml.org,2002:str"), + Node("Mars", "tag:yaml.org,2002:str"), + Node("Jupiter", "tag:yaml.org,2002:str"), + Node("Saturn", "tag:yaml.org,2002:str"), + Node("Uranus", "tag:yaml.org,2002:str"), + Node("Neptune", "tag:yaml.org,2002:str"), + Node("Pluto", "tag:yaml.org,2002:str") + ], "tag:yaml.org,2002:seq") + ) + ], + "tag:yaml.org,2002:map") + ]; +} + +Node[] constructSet() @safe +{ + return [ + Node( + [ + pair( + Node("baseball players", "tag:yaml.org,2002:str"), + Node( + [ + Node("Mark McGwire", "tag:yaml.org,2002:str"), + Node("Sammy Sosa", "tag:yaml.org,2002:str"), + Node("Ken Griffey", "tag:yaml.org,2002:str") + ], + "tag:yaml.org,2002:set") + ), + pair( + Node("baseball teams", "tag:yaml.org,2002:str"), + Node( + [ + Node("Boston Red Sox", "tag:yaml.org,2002:str"), + Node("Detroit Tigers", "tag:yaml.org,2002:str"), + Node("New York Yankees", "tag:yaml.org,2002:str") + ], + "tag:yaml.org,2002:set") + ) + ], + "tag:yaml.org,2002:map") + ]; +} + +Node[] constructStrASCII() @safe +{ + return [ + Node("ascii string", "tag:yaml.org,2002:str") + ]; +} + +Node[] constructStr() @safe +{ + return [ + Node( + [ + pair( + Node("string", "tag:yaml.org,2002:str"), + Node("abcd", "tag:yaml.org,2002:str") + ) + ], + "tag:yaml.org,2002:map") + ]; +} + +Node[] constructStrUTF8() @safe +{ + return [ + Node("\u042d\u0442\u043e \u0443\u043d\u0438\u043a\u043e\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430", "tag:yaml.org,2002:str") + ]; +} + +Node[] constructTimestamp() @safe +{ + return [ + Node( + [ + pair( + Node("canonical", "tag:yaml.org,2002:str"), + Node(SysTime(DateTime(2001, 12, 15, 2, 59, 43), 1000000.dur!"hnsecs", UTC()), "tag:yaml.org,2002:timestamp") + ), + pair( + Node("valid iso8601", "tag:yaml.org,2002:str"), + Node(SysTime(DateTime(2001, 12, 15, 2, 59, 43), 1000000.dur!"hnsecs", UTC()), "tag:yaml.org,2002:timestamp") + ), + pair( + Node("space separated", "tag:yaml.org,2002:str"), + Node(SysTime(DateTime(2001, 12, 15, 2, 59, 43), 1000000.dur!"hnsecs", UTC()), "tag:yaml.org,2002:timestamp") + ), + pair( + Node("no time zone (Z)", "tag:yaml.org,2002:str"), + Node(SysTime(DateTime(2001, 12, 15, 2, 59, 43), 1000000.dur!"hnsecs", UTC()), "tag:yaml.org,2002:timestamp") + ), + pair( + Node("date (00:00:00Z)", "tag:yaml.org,2002:str"), + Node(SysTime(DateTime(2002, 12, 14), UTC()), "tag:yaml.org,2002:timestamp") + ) + ], + "tag:yaml.org,2002:map") + ]; +} + +Node[] constructValue() @safe +{ + return [ + Node( + [ + pair( + Node("link with", "tag:yaml.org,2002:str"), + Node( + [ + Node("library1.dll", "tag:yaml.org,2002:str"), + Node("library2.dll", "tag:yaml.org,2002:str") + ], + "tag:yaml.org,2002:seq") + ) + ], + "tag:yaml.org,2002:map"), + Node( + [ + pair( + Node("link with", "tag:yaml.org,2002:str"), + Node( + [ + Node( + [ + pair( + Node("=", "tag:yaml.org,2002:value"), + Node("library1.dll", "tag:yaml.org,2002:str") + ), + pair( + Node("version", "tag:yaml.org,2002:str"), + Node(1.2L, "tag:yaml.org,2002:float") + ) + ], + "tag:yaml.org,2002:map"), + Node( + [ + pair( + Node("=", "tag:yaml.org,2002:value"), + Node("library2.dll", "tag:yaml.org,2002:str") + ), + pair( + Node("version", "tag:yaml.org,2002:str"), + Node(2.3L, "tag:yaml.org,2002:float") + ) + ], + "tag:yaml.org,2002:map") + ], + "tag:yaml.org,2002:seq") + ) + ], + "tag:yaml.org,2002:map") + ]; +} + +Node[] duplicateMergeKey() @safe +{ + return [ + Node( + [ + pair( + Node("foo", "tag:yaml.org,2002:str"), + Node("bar", "tag:yaml.org,2002:str") + ), + pair( + Node("x", "tag:yaml.org,2002:str"), + Node(1L, "tag:yaml.org,2002:int") + ), + pair( + Node("y", "tag:yaml.org,2002:str"), + Node(2L, "tag:yaml.org,2002:int") + ), + pair( + Node("z", "tag:yaml.org,2002:str"), + Node(3L, "tag:yaml.org,2002:int") + ), + pair( + Node("t", "tag:yaml.org,2002:str"), + Node(4L, "tag:yaml.org,2002:int") + ) + ], + "tag:yaml.org,2002:map") + ]; +} + +Node[] floatRepresenterBug() @safe +{ + return [ + Node( + [ + pair( + Node(1.0L, "tag:yaml.org,2002:float"), + Node(1L, "tag:yaml.org,2002:int") + ), + pair( + Node(real.infinity, "tag:yaml.org,2002:float"), + Node(10L, "tag:yaml.org,2002:int") + ), + pair( + Node(-real.infinity, "tag:yaml.org,2002:float"), + Node(-10L, "tag:yaml.org,2002:int") + ), + pair( + Node(real.nan, "tag:yaml.org,2002:float"), + Node(100L, "tag:yaml.org,2002:int") + ) + ], + "tag:yaml.org,2002:map") + ]; +} + +Node[] invalidSingleQuoteBug() @safe +{ + return [ + Node( + [ + Node("foo \'bar\'", "tag:yaml.org,2002:str"), + Node("foo\n\'bar\'", "tag:yaml.org,2002:str") + ], + "tag:yaml.org,2002:seq") + ]; +} + +Node[] moreFloats() @safe +{ + return [ + Node( + [ + Node(0.0L, "tag:yaml.org,2002:float"), + Node(1.0L, "tag:yaml.org,2002:float"), + Node(-1.0L, "tag:yaml.org,2002:float"), + Node(real.infinity, "tag:yaml.org,2002:float"), + Node(-real.infinity, "tag:yaml.org,2002:float"), + Node(real.nan, "tag:yaml.org,2002:float"), + Node(real.nan, "tag:yaml.org,2002:float") + ], + "tag:yaml.org,2002:seq") + ]; +} + +Node[] negativeFloatBug() @safe +{ + return [ + Node(-1.0L, "tag:yaml.org,2002:float") + ]; +} + +Node[] singleDotFloatBug() @safe +{ + return [ + Node(".", "tag:yaml.org,2002:str") + ]; +} + +Node[] timestampBugs() @safe +{ + return [ + Node( + [ + Node(SysTime(DateTime(2001, 12, 15, 3, 29, 43), 1000000.dur!"hnsecs", UTC()), "tag:yaml.org,2002:timestamp"), + Node(SysTime(DateTime(2001, 12, 14, 16, 29, 43), 1000000.dur!"hnsecs", UTC()), "tag:yaml.org,2002:timestamp"), + Node(SysTime(DateTime(2001, 12, 14, 21, 59, 43), 10100.dur!"hnsecs", UTC()), "tag:yaml.org,2002:timestamp"), + Node(SysTime(DateTime(2001, 12, 14, 21, 59, 43), new immutable SimpleTimeZone(60.dur!"minutes")), "tag:yaml.org,2002:timestamp"), + Node(SysTime(DateTime(2001, 12, 14, 21, 59, 43), new immutable SimpleTimeZone(-90.dur!"minutes")), "tag:yaml.org,2002:timestamp"), + Node(SysTime(DateTime(2005, 7, 8, 17, 35, 4), 5176000.dur!"hnsecs", UTC()), "tag:yaml.org,2002:timestamp") + ], + "tag:yaml.org,2002:seq") + ]; +} + +Node[] utf16be() @safe +{ + return [ + Node("UTF-16-BE", "tag:yaml.org,2002:str") + ]; +} + +Node[] utf16le() @safe +{ + return [ + Node("UTF-16-LE", "tag:yaml.org,2002:str") + ]; +} + +Node[] utf8() @safe +{ + return [ + Node("UTF-8", "tag:yaml.org,2002:str") + ]; +} + +Node[] utf8implicit() @safe +{ + return [ + Node("implicit UTF-8", "tag:yaml.org,2002:str") + ]; +} + +///Testing custom YAML class type. +class TestClass +{ + int x, y, z; + + this(int x, int y, int z) @safe + { + this.x = x; + this.y = y; + this.z = z; + } + + Node opCast(T: Node)() @safe + { + return Node( + [ + Node.Pair( + Node("x", "tag:yaml.org,2002:str"), + Node(x, "tag:yaml.org,2002:int") + ), + Node.Pair( + Node("y", "tag:yaml.org,2002:str"), + Node(y, "tag:yaml.org,2002:int") + ), + Node.Pair( + Node("z", "tag:yaml.org,2002:str"), + Node(z, "tag:yaml.org,2002:int") + ) + ], + "!tag1"); + } +} + +///Testing custom YAML struct type. +struct TestStruct +{ + int value; + + this (int x) @safe + { + value = x; + } + + ///Constructor function for TestStruct. + this(ref Node node) @safe + { + value = node.as!string.to!int; + } + + ///Representer function for TestStruct. + Node opCast(T: Node)() @safe + { + return Node(value.to!string, "!tag2"); + } +} + +} // version(unittest) + + +@safe unittest +{ + import dyaml.test.common : assertNodesEqual, run; + /** + Constructor unittest. + + Params: + dataFilename = File name to read from. + codeDummy = Dummy .code filename, used to determine that + .data file with the same name should be used in this test. + */ + static void testConstructor(string dataFilename, string codeDummy) @safe + { + string base = dataFilename.baseName.stripExtension; + assert((base in expected) !is null, "Unimplemented constructor test: " ~ base); + + auto loader = Loader.fromFile(dataFilename); + + Node[] exp = expected[base]; + + //Compare with expected results document by document. + size_t i; + foreach (node; loader) + { + assertNodesEqual(node, exp[i]); + ++i; + } + assert(i == exp.length); + } + run(&testConstructor, ["data", "code"]); +} diff --git a/src/ext_depends/D-YAML/source/dyaml/test/emitter.d b/src/ext_depends/D-YAML/source/dyaml/test/emitter.d new file mode 100644 index 0000000..293f236 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/test/emitter.d @@ -0,0 +1,132 @@ + +// Copyright Ferdinand Majerech 2011-2014. +// 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) + +module dyaml.test.emitter; + +@safe unittest +{ + import std.array : Appender; + import std.range : ElementType, isInputRange; + + import dyaml : CollectionStyle, LineBreak, Loader, Mark, ScalarStyle; + import dyaml.emitter : Emitter; + import dyaml.event : Event, EventID, mappingStartEvent, scalarEvent, sequenceStartEvent; + import dyaml.test.common : assertEventsEqual, run; + + // Try to emit an event range. + static void emitTestCommon(T)(ref Appender!string emitStream, T events, bool canonical = false) @safe + if (isInputRange!T && is(ElementType!T == Event)) + { + auto emitter = Emitter!(typeof(emitStream), char)(emitStream, canonical, 2, 80, LineBreak.unix); + foreach (ref event; events) + { + emitter.emit(event); + } + } + /** + Test emitter by getting events from parsing a file, emitting them, parsing + the emitted result and comparing events from parsing the emitted result with + originally parsed events. + + Params: + dataFilename = YAML file to parse. + canonicalFilename = Canonical YAML file used as dummy to determine + which data files to load. + */ + static void testEmitterOnData(string dataFilename, string canonicalFilename) @safe + { + //Must exist due to Anchor, Tags reference counts. + auto loader = Loader.fromFile(dataFilename); + auto events = loader.parse(); + auto emitStream = Appender!string(); + emitTestCommon(emitStream, events); + + auto loader2 = Loader.fromString(emitStream.data); + loader2.name = "TEST"; + auto newEvents = loader2.parse(); + assertEventsEqual(events, newEvents); + } + /** + Test emitter by getting events from parsing a canonical YAML file, emitting + them both in canonical and normal format, parsing the emitted results and + comparing events from parsing the emitted result with originally parsed events. + + Params: canonicalFilename = Canonical YAML file to parse. + */ + static void testEmitterOnCanonical(string canonicalFilename) @safe + { + //Must exist due to Anchor, Tags reference counts. + auto loader = Loader.fromFile(canonicalFilename); + auto events = loader.parse(); + foreach (canonical; [false, true]) + { + auto emitStream = Appender!string(); + emitTestCommon(emitStream, events, canonical); + + auto loader2 = Loader.fromString(emitStream.data); + loader2.name = "TEST"; + auto newEvents = loader2.parse(); + assertEventsEqual(events, newEvents); + } + } + /** + Test emitter by getting events from parsing a file, emitting them with all + possible scalar and collection styles, parsing the emitted results and + comparing events from parsing the emitted result with originally parsed events. + + Params: + dataFilename = YAML file to parse. + canonicalFilename = Canonical YAML file used as dummy to determine + which data files to load. + */ + static void testEmitterStyles(string dataFilename, string canonicalFilename) @safe + { + foreach (filename; [dataFilename, canonicalFilename]) + { + //must exist due to Anchor, Tags reference counts + auto loader = Loader.fromFile(canonicalFilename); + auto events = loader.parse(); + foreach (flowStyle; [CollectionStyle.block, CollectionStyle.flow]) + { + foreach (style; [ScalarStyle.literal, ScalarStyle.folded, + ScalarStyle.doubleQuoted, ScalarStyle.singleQuoted, + ScalarStyle.plain]) + { + Event[] styledEvents; + foreach (event; events) + { + if (event.id == EventID.scalar) + { + event = scalarEvent(Mark(), Mark(), event.anchor, event.tag, + event.implicit, + event.value, style); + } + else if (event.id == EventID.sequenceStart) + { + event = sequenceStartEvent(Mark(), Mark(), event.anchor, + event.tag, event.implicit, flowStyle); + } + else if (event.id == EventID.mappingStart) + { + event = mappingStartEvent(Mark(), Mark(), event.anchor, + event.tag, event.implicit, flowStyle); + } + styledEvents ~= event; + } + auto emitStream = Appender!string(); + emitTestCommon(emitStream, styledEvents); + auto loader2 = Loader.fromString(emitStream.data); + loader2.name = "TEST"; + auto newEvents = loader2.parse(); + assertEventsEqual(events, newEvents); + } + } + } + } + run(&testEmitterOnData, ["data", "canonical"]); + run(&testEmitterOnCanonical, ["canonical"]); + run(&testEmitterStyles, ["data", "canonical"]); +} diff --git a/src/ext_depends/D-YAML/source/dyaml/test/errors.d b/src/ext_depends/D-YAML/source/dyaml/test/errors.d new file mode 100644 index 0000000..43b019c --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/test/errors.d @@ -0,0 +1,64 @@ + +// Copyright Ferdinand Majerech 2011-2014 +// 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) + +module dyaml.test.errors; + +@safe unittest +{ + import std.array : array; + import std.exception : assertThrown; + + import dyaml : Loader; + import dyaml.test.common : run; + + /** + Loader error unittest from file stream. + + Params: errorFilename = File name to read from. + */ + static void testLoaderError(string errorFilename) @safe + { + assertThrown(Loader.fromFile(errorFilename).array, + __FUNCTION__ ~ "(" ~ errorFilename ~ ") Expected an exception"); + } + + /** + Loader error unittest from string. + + Params: errorFilename = File name to read from. + */ + static void testLoaderErrorString(string errorFilename) @safe + { + assertThrown(Loader.fromFile(errorFilename).array, + __FUNCTION__ ~ "(" ~ errorFilename ~ ") Expected an exception"); + } + + /** + Loader error unittest from filename. + + Params: errorFilename = File name to read from. + */ + static void testLoaderErrorFilename(string errorFilename) @safe + { + assertThrown(Loader.fromFile(errorFilename).array, + __FUNCTION__ ~ "(" ~ errorFilename ~ ") Expected an exception"); + } + + /** + Loader error unittest loading a single document from a file. + + Params: errorFilename = File name to read from. + */ + static void testLoaderErrorSingle(string errorFilename) @safe + { + assertThrown(Loader.fromFile(errorFilename).load(), + __FUNCTION__ ~ "(" ~ errorFilename ~ ") Expected an exception"); + } + run(&testLoaderError, ["loader-error"]); + run(&testLoaderErrorString, ["loader-error"]); + run(&testLoaderErrorFilename, ["loader-error"]); + run(&testLoaderErrorSingle, ["single-loader-error"]); +} diff --git a/src/ext_depends/D-YAML/source/dyaml/test/inputoutput.d b/src/ext_depends/D-YAML/source/dyaml/test/inputoutput.d new file mode 100644 index 0000000..758def8 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/test/inputoutput.d @@ -0,0 +1,92 @@ + +// Copyright Ferdinand Majerech 2011-2014. +// 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) + +module dyaml.test.inputoutput; + +@safe unittest +{ + import std.array : join, split; + import std.conv : to; + import std.exception : assertThrown; + import std.file : readText; + import std.system : endian, Endian; + + import dyaml : Loader, Node, YAMLException; + import dyaml.test.common : run; + + /** + Get an UTF-16 byte order mark. + + Params: wrong = Get the incorrect BOM for this system. + + Returns: UTF-16 byte order mark. + */ + static wchar bom16(bool wrong = false) pure @safe + { + wchar little = '\uFEFF'; + wchar big = '\uFFFE'; + if (!wrong) + { + return endian == Endian.littleEndian ? little : big; + } + return endian == Endian.littleEndian ? big : little; + } + /** + Get an UTF-32 byte order mark. + + Params: wrong = Get the incorrect BOM for this system. + + Returns: UTF-32 byte order mark. + */ + static dchar bom32(bool wrong = false) pure @safe + { + dchar little = '\uFEFF'; + dchar big = '\uFFFE'; + if (!wrong) + { + return endian == Endian.littleEndian ? little : big; + } + return endian == Endian.littleEndian ? big : little; + } + /** + Unicode input unittest. Tests various encodings. + + Params: unicodeFilename = File name to read from. + */ + static void testUnicodeInput(string unicodeFilename) @safe + { + string data = readText(unicodeFilename); + string expected = data.split().join(" "); + + Node output = Loader.fromString(data).load(); + assert(output.as!string == expected); + + foreach (buffer; [cast(ubyte[]) (bom16() ~ data.to!(wchar[])), + cast(ubyte[]) (bom32() ~ data.to!(dchar[]))]) + { + output = Loader.fromBuffer(buffer).load(); + assert(output.as!string == expected); + } + } + /** + Unicode input error unittest. Tests various encodings with incorrect BOMs. + + Params: unicodeFilename = File name to read from. + */ + static void testUnicodeInputErrors(string unicodeFilename) @safe + { + string data = readText(unicodeFilename); + foreach (buffer; [cast(ubyte[]) (data.to!(wchar[])), + cast(ubyte[]) (data.to!(dchar[])), + cast(ubyte[]) (bom16(true) ~ data.to!(wchar[])), + cast(ubyte[]) (bom32(true) ~ data.to!(dchar[]))]) + { + assertThrown(Loader.fromBuffer(buffer).load()); + } + } + run(&testUnicodeInput, ["unicode"]); + run(&testUnicodeInputErrors, ["unicode"]); +} diff --git a/src/ext_depends/D-YAML/source/dyaml/test/reader.d b/src/ext_depends/D-YAML/source/dyaml/test/reader.d new file mode 100644 index 0000000..c20df6f --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/test/reader.d @@ -0,0 +1,37 @@ + +// 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) + +module dyaml.test.reader; + +@safe unittest +{ + import std.exception :assertThrown; + + import dyaml.test.common : readData, run; + import dyaml.reader : Reader, ReaderException; + + /** + Try reading entire file through Reader, expecting an error (the file is invalid). + + Params: data = Stream to read. + */ + static void runReader(ubyte[] fileData) @safe + { + auto reader = new Reader(fileData); + while(reader.peek() != '\0') { reader.forward(); } + } + + /** + Stream error unittest. Tries to read invalid input files, expecting errors. + + Params: errorFilename = File name to read from. + */ + static void testStreamError(string errorFilename) @safe + { + assertThrown!ReaderException(runReader(readData(errorFilename))); + } + run(&testStreamError, ["stream-error"]); +} diff --git a/src/ext_depends/D-YAML/source/dyaml/test/representer.d b/src/ext_depends/D-YAML/source/dyaml/test/representer.d new file mode 100644 index 0000000..4a1ae67 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/test/representer.d @@ -0,0 +1,54 @@ + +// 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) + +module dyaml.test.representer; + +@safe unittest +{ + import std.array : Appender, array; + import std.meta : AliasSeq; + import std.path : baseName, stripExtension; + import std.utf : toUTF8; + + import dyaml : dumper, Loader, Node; + import dyaml.test.common : assertNodesEqual, run; + import dyaml.test.constructor : expected; + + /** + Representer unittest. Dumps nodes, then loads them again. + + Params: + baseName = Nodes in dyaml.test.constructor.expected for roundtripping. + */ + static void testRepresenterTypes(string baseName) @safe + { + assert((baseName in expected) !is null, "Unimplemented representer test: " ~ baseName); + + Node[] expectedNodes = expected[baseName]; + foreach (encoding; AliasSeq!(char, wchar, dchar)) + { + auto emitStream = new Appender!(immutable(encoding)[]); + auto dumper = dumper(); + dumper.dump!encoding(emitStream, expectedNodes); + + immutable output = emitStream.data; + + auto loader = Loader.fromString(emitStream.data.toUTF8); + loader.name = "TEST"; + const readNodes = loader.array; + + assert(expectedNodes.length == readNodes.length); + foreach (n; 0 .. expectedNodes.length) + { + assertNodesEqual(expectedNodes[n], readNodes[n]); + } + } + } + foreach (key, _; expected) + { + testRepresenterTypes(key); + } +} diff --git a/src/ext_depends/D-YAML/source/dyaml/test/resolver.d b/src/ext_depends/D-YAML/source/dyaml/test/resolver.d new file mode 100644 index 0000000..ea93720 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/test/resolver.d @@ -0,0 +1,39 @@ + +// 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) + +module dyaml.test.resolver; + +@safe unittest +{ + import std.conv : text; + import std.file : readText; + import std.string : strip; + + import dyaml : Loader, Node, NodeID; + import dyaml.test.common : run; + + + /** + Implicit tag resolution unittest. + + Params: + dataFilename = File with unittest data. + detectFilename = Dummy filename used to specify which data filenames to use. + */ + static void testImplicitResolver(string dataFilename, string detectFilename) @safe + { + const correctTag = readText(detectFilename).strip(); + + auto node = Loader.fromFile(dataFilename).load(); + assert(node.nodeID == NodeID.sequence, text("Expected sequence when reading '", dataFilename, "', got ", node.nodeID)); + foreach (Node scalar; node) + { + assert(scalar.nodeID == NodeID.scalar, text("Expected sequence of scalars when reading '", dataFilename, "', got sequence of ", scalar.nodeID)); + assert(scalar.tag == correctTag, text("Expected tag '", correctTag, "' when reading '", dataFilename, "', got '", scalar.tag, "'")); + } + } + run(&testImplicitResolver, ["data", "detect"]); +} diff --git a/src/ext_depends/D-YAML/source/dyaml/test/tokens.d b/src/ext_depends/D-YAML/source/dyaml/test/tokens.d new file mode 100644 index 0000000..c099647 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/test/tokens.d @@ -0,0 +1,93 @@ + +// 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) + +module dyaml.test.tokens; + +@safe unittest +{ + import std.array : split; + import std.conv : text; + import std.file : readText; + + import dyaml.test.common : run; + import dyaml.reader : Reader; + import dyaml.scanner : Scanner; + import dyaml.token : TokenID; + + // Read and scan a YAML doc, returning a range of tokens. + static auto scanTestCommon(string filename) @safe + { + ubyte[] yamlData = cast(ubyte[])readText(filename).dup; + return Scanner(new Reader(yamlData)); + } + + /** + Test tokens output by scanner. + + Params: + dataFilename = File to scan. + tokensFilename = File containing expected tokens. + */ + static void testTokens(string dataFilename, string tokensFilename) @safe + { + //representations of YAML tokens in tokens file. + auto replace = [ + TokenID.directive: "%", + TokenID.documentStart: "---", + TokenID.documentEnd: "...", + TokenID.alias_: "*", + TokenID.anchor: "&", + TokenID.tag: "!", + TokenID.scalar: "_", + TokenID.blockSequenceStart: "[[", + TokenID.blockMappingStart: "{{", + TokenID.blockEnd: "]}", + TokenID.flowSequenceStart: "[", + TokenID.flowSequenceEnd: "]", + TokenID.flowMappingStart: "{", + TokenID.flowMappingEnd: "}", + TokenID.blockEntry: ",", + TokenID.flowEntry: ",", + TokenID.key: "?", + TokenID.value: ":" + ]; + + string[] tokens; + string[] expectedTokens = readText(tokensFilename).split(); + + foreach (token; scanTestCommon(dataFilename)) + { + if (token.id != TokenID.streamStart && token.id != TokenID.streamEnd) + { + tokens ~= replace[token.id]; + } + } + + assert(tokens == expectedTokens, + text("In token test for '", tokensFilename, "', expected '", expectedTokens, "', got '", tokens, "'")); + } + + /** + Test scanner by scanning a file, expecting no errors. + + Params: + dataFilename = File to scan. + canonicalFilename = Another file to scan, in canonical YAML format. + */ + static void testScanner(string dataFilename, string canonicalFilename) @safe + { + foreach (filename; [dataFilename, canonicalFilename]) + { + string[] tokens; + foreach (token; scanTestCommon(filename)) + { + tokens ~= token.id.text; + } + } + } + run(&testTokens, ["data", "tokens"]); + run(&testScanner, ["data", "canonical"]); +} diff --git a/src/ext_depends/D-YAML/source/dyaml/tinyendian.d b/src/ext_depends/D-YAML/source/dyaml/tinyendian.d new file mode 100644 index 0000000..731b048 --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/tinyendian.d @@ -0,0 +1,213 @@ +// Copyright Ferdinand Majerech 2014. +// 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) + +/// A minimal library providing functionality for changing the endianness of data. +module tinyendian; + +import std.system : Endian, endian; + +/// Unicode UTF encodings. +enum UTFEncoding : ubyte +{ + UTF_8, + UTF_16, + UTF_32 +} +/// +@safe unittest +{ + const ints = [314, -101]; + int[2] intsSwapBuffer = ints; + swapByteOrder(intsSwapBuffer[]); + swapByteOrder(intsSwapBuffer[]); + assert(ints == intsSwapBuffer, "Lost information when swapping byte order"); + + const floats = [3.14f, 10.1f]; + float[2] floatsSwapBuffer = floats; + swapByteOrder(floatsSwapBuffer[]); + swapByteOrder(floatsSwapBuffer[]); + assert(floats == floatsSwapBuffer, "Lost information when swapping byte order"); +} + +/** Swap byte order of items in an array in place. + * + * Params: + * + * T = Item type. Must be either 2 or 4 bytes long. + * array = Buffer with values to fix byte order of. + */ +void swapByteOrder(T)(T[] array) @trusted @nogc pure nothrow +if (T.sizeof == 2 || T.sizeof == 4) +{ + // Swap the byte order of all read characters. + foreach (ref item; array) + { + static if (T.sizeof == 2) + { + import std.algorithm.mutation : swap; + swap(*cast(ubyte*)&item, *(cast(ubyte*)&item + 1)); + } + else static if (T.sizeof == 4) + { + import core.bitop : bswap; + const swapped = bswap(*cast(uint*)&item); + item = *cast(const(T)*)&swapped; + } + else static assert(false, "Unsupported T: " ~ T.stringof); + } +} + +/// See fixUTFByteOrder. +struct FixUTFByteOrderResult +{ + ubyte[] array; + UTFEncoding encoding; + Endian endian; + uint bytesStripped = 0; +} + +/** Convert byte order of an array encoded in UTF(8/16/32) to system endianness in place. + * + * Uses the UTF byte-order-mark (BOM) to determine UTF encoding. If there is no BOM + * at the beginning of array, UTF-8 is assumed (this is compatible with ASCII). The + * BOM, if any, will be removed from the buffer. + * + * If the encoding is determined to be UTF-16 or UTF-32 and there aren't enough bytes + * for the last code unit (i.e. if array.length is odd for UTF-16 or not divisible by + * 4 for UTF-32), the extra bytes (1 for UTF-16, 1-3 for UTF-32) are stripped. + * + * Note that this function does $(B not) check if the array is a valid UTF string. It + * only works with the BOM and 1,2 or 4-byte items. + * + * Params: + * + * array = The array with UTF-data. + * + * Returns: + * + * A struct with the following members: + * + * $(D ubyte[] array) A slice of the input array containing data in correct + * byte order, without BOM and in case of UTF-16/UTF-32, + * without stripped bytes, if any. + * $(D UTFEncoding encoding) Encoding of the result (UTF-8, UTF-16 or UTF-32) + * $(D std.system.Endian endian) Endianness of the original array. + * $(D uint bytesStripped) Number of bytes stripped from a UTF-16/UTF-32 array, if + * any. This is non-zero only if array.length was not + * divisible by 2 or 4 for UTF-16 and UTF-32, respectively. + * + * Complexity: (BIGOH array.length) + */ +auto fixUTFByteOrder(ubyte[] array) @safe @nogc pure nothrow +{ + // Enumerates UTF BOMs, matching indices to byteOrderMarks/bomEndian. + enum BOM: ubyte + { + UTF_8 = 0, + UTF_16_LE = 1, + UTF_16_BE = 2, + UTF_32_LE = 3, + UTF_32_BE = 4, + None = ubyte.max + } + + // These 2 are from std.stream + static immutable ubyte[][5] byteOrderMarks = [ [0xEF, 0xBB, 0xBF], + [0xFF, 0xFE], + [0xFE, 0xFF], + [0xFF, 0xFE, 0x00, 0x00], + [0x00, 0x00, 0xFE, 0xFF] ]; + static immutable Endian[5] bomEndian = [ endian, + Endian.littleEndian, + Endian.bigEndian, + Endian.littleEndian, + Endian.bigEndian ]; + + // Documented in function ddoc. + + FixUTFByteOrderResult result; + + // Detect BOM, if any, in the bytes we've read. -1 means no BOM. + // Need the last match: First 2 bytes of UTF-32LE BOM match the UTF-16LE BOM. If we + // used the first match, UTF-16LE would be detected when we have a UTF-32LE BOM. + import std.algorithm.searching : startsWith; + BOM bomId = BOM.None; + foreach (i, bom; byteOrderMarks) + if (array.startsWith(bom)) + bomId = cast(BOM)i; + + result.endian = (bomId != BOM.None) ? bomEndian[bomId] : Endian.init; + + // Start of UTF data (after BOM, if any) + size_t start = 0; + // If we've read more than just the BOM, put the rest into the array. + with(BOM) final switch(bomId) + { + case None: result.encoding = UTFEncoding.UTF_8; break; + case UTF_8: + start = 3; + result.encoding = UTFEncoding.UTF_8; + break; + case UTF_16_LE, UTF_16_BE: + result.bytesStripped = array.length % 2; + start = 2; + result.encoding = UTFEncoding.UTF_16; + break; + case UTF_32_LE, UTF_32_BE: + result.bytesStripped = array.length % 4; + start = 4; + result.encoding = UTFEncoding.UTF_32; + break; + } + + // If there's a BOM, we need to move data back to ensure it starts at array[0] + if (start != 0) + { + array = array[start .. $ - result.bytesStripped]; + } + + // We enforce above that array.length is divisible by 2/4 for UTF-16/32 + if (endian != result.endian) + { + if (result.encoding == UTFEncoding.UTF_16) + swapByteOrder(cast(wchar[])array); + else if (result.encoding == UTFEncoding.UTF_32) + swapByteOrder(cast(dchar[])array); + } + + result.array = array; + return result; +} +/// +@safe unittest +{ + { + ubyte[] s = [0xEF, 0xBB, 0xBF, 'a']; + FixUTFByteOrderResult r = fixUTFByteOrder(s); + assert(r.encoding == UTFEncoding.UTF_8); + assert(r.array.length == 1); + assert(r.array == ['a']); + assert(r.endian == Endian.littleEndian); + } + + { + ubyte[] s = ['a']; + FixUTFByteOrderResult r = fixUTFByteOrder(s); + assert(r.encoding == UTFEncoding.UTF_8); + assert(r.array.length == 1); + assert(r.array == ['a']); + assert(r.endian == Endian.bigEndian); + } + + { + // strip 'a' b/c not complete unit + ubyte[] s = [0xFE, 0xFF, 'a']; + FixUTFByteOrderResult r = fixUTFByteOrder(s); + assert(r.encoding == UTFEncoding.UTF_16); + assert(r.array.length == 0); + assert(r.endian == Endian.bigEndian); + } + +} diff --git a/src/ext_depends/D-YAML/source/dyaml/token.d b/src/ext_depends/D-YAML/source/dyaml/token.d new file mode 100644 index 0000000..5400a3f --- /dev/null +++ b/src/ext_depends/D-YAML/source/dyaml/token.d @@ -0,0 +1,172 @@ + +// Copyright Ferdinand Majerech 2011-2014. +// 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) + +/// YAML tokens. +/// Code based on PyYAML: http://www.pyyaml.org +module dyaml.token; + + +import std.conv; + +import dyaml.encoding; +import dyaml.exception; +import dyaml.reader; +import dyaml.style; + + +package: + +/// Token types. +enum TokenID : ubyte +{ + // Invalid (uninitialized) token + invalid = 0, + directive, + documentStart, + documentEnd, + streamStart, + streamEnd, + blockSequenceStart, + blockMappingStart, + blockEnd, + flowSequenceStart, + flowMappingStart, + flowSequenceEnd, + flowMappingEnd, + key, + value, + blockEntry, + flowEntry, + alias_, + anchor, + tag, + scalar +} + +/// Specifies the type of a tag directive token. +enum DirectiveType : ubyte +{ + // YAML version directive. + yaml, + // Tag directive. + tag, + // Any other directive is "reserved" for future YAML versions. + reserved +} + +/// Token produced by scanner. +/// +/// 32 bytes on 64-bit. +struct Token +{ + @disable int opCmp(ref Token); + + // 16B + /// Value of the token, if any. + /// + /// Values are char[] instead of string, as Parser may still change them in a few + /// cases. Parser casts values to strings when producing Events. + char[] value; + // 4B + /// Start position of the token in file/stream. + Mark startMark; + // 4B + /// End position of the token in file/stream. + Mark endMark; + // 1B + /// Token type. + TokenID id; + // 1B + /// Style of scalar token, if this is a scalar token. + ScalarStyle style; + // 1B + /// Encoding, if this is a stream start token. + Encoding encoding; + // 1B + /// Type of directive for directiveToken. + DirectiveType directive; + // 4B + /// Used to split value into 2 substrings for tokens that need 2 values (tagToken) + uint valueDivider; + + /// Get string representation of the token ID. + @property string idString() @safe pure const {return id.to!string;} +} + +/// Construct a directive token. +/// +/// Params: start = Start position of the token. +/// end = End position of the token. +/// value = Value of the token. +/// directive = Directive type (YAML or TAG in YAML 1.1). +/// nameEnd = Position of the end of the name +Token directiveToken(const Mark start, const Mark end, char[] value, + DirectiveType directive, const uint nameEnd) @safe pure nothrow @nogc +{ + return Token(value, start, end, TokenID.directive, ScalarStyle.init, Encoding.init, + directive, nameEnd); +} + +/// Construct a simple (no value) token with specified type. +/// +/// Params: id = Type of the token. +/// start = Start position of the token. +/// end = End position of the token. +Token simpleToken(TokenID id)(const Mark start, const Mark end) +{ + return Token(null, start, end, id); +} + +/// Construct a stream start token. +/// +/// Params: start = Start position of the token. +/// end = End position of the token. +/// encoding = Encoding of the stream. +Token streamStartToken(const Mark start, const Mark end, const Encoding encoding) @safe pure nothrow @nogc +{ + return Token(null, start, end, TokenID.streamStart, ScalarStyle.invalid, encoding); +} + +/// Aliases for construction of simple token types. +alias streamEndToken = simpleToken!(TokenID.streamEnd); +alias blockSequenceStartToken = simpleToken!(TokenID.blockSequenceStart); +alias blockMappingStartToken = simpleToken!(TokenID.blockMappingStart); +alias blockEndToken = simpleToken!(TokenID.blockEnd); +alias keyToken = simpleToken!(TokenID.key); +alias valueToken = simpleToken!(TokenID.value); +alias blockEntryToken = simpleToken!(TokenID.blockEntry); +alias flowEntryToken = simpleToken!(TokenID.flowEntry); + +/// Construct a simple token with value with specified type. +/// +/// Params: id = Type of the token. +/// start = Start position of the token. +/// end = End position of the token. +/// value = Value of the token. +/// valueDivider = A hack for TagToken to store 2 values in value; the first +/// value goes up to valueDivider, the second after it. +Token simpleValueToken(TokenID id)(const Mark start, const Mark end, char[] value, + const uint valueDivider = uint.max) +{ + return Token(value, start, end, id, ScalarStyle.invalid, Encoding.init, + DirectiveType.init, valueDivider); +} + +/// Alias for construction of tag token. +alias tagToken = simpleValueToken!(TokenID.tag); +alias aliasToken = simpleValueToken!(TokenID.alias_); +alias anchorToken = simpleValueToken!(TokenID.anchor); + +/// Construct a scalar token. +/// +/// Params: start = Start position of the token. +/// end = End position of the token. +/// value = Value of the token. +/// style = Style of the token. +Token scalarToken(const Mark start, const Mark end, char[] value, const ScalarStyle style) @safe pure nothrow @nogc +{ + return Token(value, start, end, TokenID.scalar, style); +} diff --git a/src/ext_depends/D-YAML/test/data/a-nasty-libyaml-bug.loader-error b/src/ext_depends/D-YAML/test/data/a-nasty-libyaml-bug.loader-error new file mode 100644 index 0000000..f97d49f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/a-nasty-libyaml-bug.loader-error @@ -0,0 +1 @@ +[ [
\ No newline at end of file diff --git a/src/ext_depends/D-YAML/test/data/aliases-cdumper-bug.code b/src/ext_depends/D-YAML/test/data/aliases-cdumper-bug.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/aliases-cdumper-bug.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/aliases.events b/src/ext_depends/D-YAML/test/data/aliases.events new file mode 100644 index 0000000..9139b51 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/aliases.events @@ -0,0 +1,8 @@ +- !StreamStart +- !DocumentStart +- !SequenceStart +- !Scalar { anchor: 'myanchor', tag: '!mytag', value: 'data' } +- !Alias { anchor: 'myanchor' } +- !SequenceEnd +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/bmpchars.canonical b/src/ext_depends/D-YAML/test/data/bmpchars.canonical new file mode 100644 index 0000000..9b77b57 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/bmpchars.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!map { + ? !!str "a" + : !!str "𒅗" +} diff --git a/src/ext_depends/D-YAML/test/data/bmpchars.data b/src/ext_depends/D-YAML/test/data/bmpchars.data new file mode 100644 index 0000000..28e948e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/bmpchars.data @@ -0,0 +1 @@ +a: 𒅗
\ No newline at end of file diff --git a/src/ext_depends/D-YAML/test/data/bool.data b/src/ext_depends/D-YAML/test/data/bool.data new file mode 100644 index 0000000..0988b63 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/bool.data @@ -0,0 +1,4 @@ +- yes +- NO +- True +- on diff --git a/src/ext_depends/D-YAML/test/data/bool.detect b/src/ext_depends/D-YAML/test/data/bool.detect new file mode 100644 index 0000000..947ebbb --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/bool.detect @@ -0,0 +1 @@ +tag:yaml.org,2002:bool diff --git a/src/ext_depends/D-YAML/test/data/colon-in-flow-context.loader-error b/src/ext_depends/D-YAML/test/data/colon-in-flow-context.loader-error new file mode 100644 index 0000000..13d5087 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/colon-in-flow-context.loader-error @@ -0,0 +1 @@ +{ foo:bar } diff --git a/src/ext_depends/D-YAML/test/data/construct-binary.code b/src/ext_depends/D-YAML/test/data/construct-binary.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-binary.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-binary.data b/src/ext_depends/D-YAML/test/data/construct-binary.data new file mode 100644 index 0000000..dcdb16f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-binary.data @@ -0,0 +1,12 @@ +canonical: !!binary "\ + R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5\ + OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+\ + +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC\ + AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=" +generic: !!binary | + R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5 + OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+ + +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC + AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs= +description: + The binary value above is a tiny arrow encoded as a gif image. diff --git a/src/ext_depends/D-YAML/test/data/construct-bool.code b/src/ext_depends/D-YAML/test/data/construct-bool.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-bool.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-bool.data b/src/ext_depends/D-YAML/test/data/construct-bool.data new file mode 100644 index 0000000..4c0b757 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-bool.data @@ -0,0 +1,13 @@ +canonical: yes +answer: NO +logical: True +option: on +constbool: on +imutbool: on +const_bool: on +imut_bool: on + + +but: + y: is a string + n: is a string diff --git a/src/ext_depends/D-YAML/test/data/construct-custom.code b/src/ext_depends/D-YAML/test/data/construct-custom.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-custom.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-custom.data b/src/ext_depends/D-YAML/test/data/construct-custom.data new file mode 100644 index 0000000..f17e4ed --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-custom.data @@ -0,0 +1,7 @@ +--- +- !tag1 + x: 1 + 'y': 2 + z: 3 +- !tag2 + 10 diff --git a/src/ext_depends/D-YAML/test/data/construct-float.code b/src/ext_depends/D-YAML/test/data/construct-float.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-float.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-float.data b/src/ext_depends/D-YAML/test/data/construct-float.data new file mode 100644 index 0000000..b662c62 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-float.data @@ -0,0 +1,6 @@ +canonical: 6.8523015e+5 +exponential: 685.230_15e+03 +fixed: 685_230.15 +sexagesimal: 190:20:30.15 +negative infinity: -.inf +not a number: .NaN diff --git a/src/ext_depends/D-YAML/test/data/construct-int.code b/src/ext_depends/D-YAML/test/data/construct-int.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-int.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-int.data b/src/ext_depends/D-YAML/test/data/construct-int.data new file mode 100644 index 0000000..852c314 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-int.data @@ -0,0 +1,6 @@ +canonical: 685230 +decimal: +685_230 +octal: 02472256 +hexadecimal: 0x_0A_74_AE +binary: 0b1010_0111_0100_1010_1110 +sexagesimal: 190:20:30 diff --git a/src/ext_depends/D-YAML/test/data/construct-map.code b/src/ext_depends/D-YAML/test/data/construct-map.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-map.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-map.data b/src/ext_depends/D-YAML/test/data/construct-map.data new file mode 100644 index 0000000..022446d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-map.data @@ -0,0 +1,6 @@ +# Unordered set of key: value pairs. +Block style: !!map + Clark : Evans + Brian : Ingerson + Oren : Ben-Kiki +Flow style: !!map { Clark: Evans, Brian: Ingerson, Oren: Ben-Kiki } diff --git a/src/ext_depends/D-YAML/test/data/construct-merge.code b/src/ext_depends/D-YAML/test/data/construct-merge.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-merge.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-merge.data b/src/ext_depends/D-YAML/test/data/construct-merge.data new file mode 100644 index 0000000..3fdb2e2 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-merge.data @@ -0,0 +1,27 @@ +--- +- &CENTER { x: 1, 'y': 2 } +- &LEFT { x: 0, 'y': 2 } +- &BIG { r: 10 } +- &SMALL { r: 1 } + +# All the following maps are equal: + +- # Explicit keys + x: 1 + 'y': 2 + r: 10 + label: center/big + +- # Merge one map + << : *CENTER + r: 10 + label: center/big + +- # Merge multiple maps + << : [ *CENTER, *BIG ] + label: center/big + +- # Override + << : [ *BIG, *LEFT, *SMALL ] + x: 1 + label: center/big diff --git a/src/ext_depends/D-YAML/test/data/construct-null.code b/src/ext_depends/D-YAML/test/data/construct-null.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-null.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-null.data b/src/ext_depends/D-YAML/test/data/construct-null.data new file mode 100644 index 0000000..9ad0344 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-null.data @@ -0,0 +1,18 @@ +# A document may be null. +--- +--- +# This mapping has four keys, +# one has a value. +empty: +canonical: ~ +english: null +~: null key +--- +# This sequence has five +# entries, two have values. +sparse: + - ~ + - 2nd entry + - + - 4th entry + - Null diff --git a/src/ext_depends/D-YAML/test/data/construct-omap.code b/src/ext_depends/D-YAML/test/data/construct-omap.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-omap.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-omap.data b/src/ext_depends/D-YAML/test/data/construct-omap.data new file mode 100644 index 0000000..4fa0f45 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-omap.data @@ -0,0 +1,8 @@ +# Explicitly typed ordered map (dictionary). +Bestiary: !!omap + - aardvark: African pig-like ant eater. Ugly. + - anteater: South-American ant eater. Two species. + - anaconda: South-American constrictor snake. Scaly. + # Etc. +# Flow style +Numbers: !!omap [ one: 1, two: 2, three : 3 ] diff --git a/src/ext_depends/D-YAML/test/data/construct-pairs.code b/src/ext_depends/D-YAML/test/data/construct-pairs.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-pairs.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-pairs.data b/src/ext_depends/D-YAML/test/data/construct-pairs.data new file mode 100644 index 0000000..05f55b9 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-pairs.data @@ -0,0 +1,7 @@ +# Explicitly typed pairs. +Block tasks: !!pairs + - meeting: with team. + - meeting: with boss. + - break: lunch. + - meeting: with client. +Flow tasks: !!pairs [ meeting: with team, meeting: with boss ] diff --git a/src/ext_depends/D-YAML/test/data/construct-seq.code b/src/ext_depends/D-YAML/test/data/construct-seq.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-seq.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-seq.data b/src/ext_depends/D-YAML/test/data/construct-seq.data new file mode 100644 index 0000000..bb92fd1 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-seq.data @@ -0,0 +1,15 @@ +# Ordered sequence of nodes +Block style: !!seq +- Mercury # Rotates - no light/dark sides. +- Venus # Deadliest. Aptly named. +- Earth # Mostly dirt. +- Mars # Seems empty. +- Jupiter # The king. +- Saturn # Pretty. +- Uranus # Where the sun hardly shines. +- Neptune # Boring. No rings. +- Pluto # You call this a planet? +Flow style: !!seq [ Mercury, Venus, Earth, Mars, # Rocks + Jupiter, Saturn, Uranus, Neptune, # Gas + Pluto ] # Overrated + diff --git a/src/ext_depends/D-YAML/test/data/construct-set.code b/src/ext_depends/D-YAML/test/data/construct-set.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-set.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-set.data b/src/ext_depends/D-YAML/test/data/construct-set.data new file mode 100644 index 0000000..e05dc88 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-set.data @@ -0,0 +1,7 @@ +# Explicitly typed set. +baseball players: !!set + ? Mark McGwire + ? Sammy Sosa + ? Ken Griffey +# Flow style +baseball teams: !!set { Boston Red Sox, Detroit Tigers, New York Yankees } diff --git a/src/ext_depends/D-YAML/test/data/construct-str-ascii.code b/src/ext_depends/D-YAML/test/data/construct-str-ascii.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-str-ascii.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-str-ascii.data b/src/ext_depends/D-YAML/test/data/construct-str-ascii.data new file mode 100644 index 0000000..0d93013 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-str-ascii.data @@ -0,0 +1 @@ +--- !!str "ascii string" diff --git a/src/ext_depends/D-YAML/test/data/construct-str-utf8.code b/src/ext_depends/D-YAML/test/data/construct-str-utf8.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-str-utf8.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-str-utf8.data b/src/ext_depends/D-YAML/test/data/construct-str-utf8.data new file mode 100644 index 0000000..e355f18 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-str-utf8.data @@ -0,0 +1 @@ +--- !!str "Это уникодная строка" diff --git a/src/ext_depends/D-YAML/test/data/construct-str.code b/src/ext_depends/D-YAML/test/data/construct-str.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-str.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-str.data b/src/ext_depends/D-YAML/test/data/construct-str.data new file mode 100644 index 0000000..606ac6b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-str.data @@ -0,0 +1 @@ +string: abcd diff --git a/src/ext_depends/D-YAML/test/data/construct-timestamp.code b/src/ext_depends/D-YAML/test/data/construct-timestamp.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-timestamp.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-timestamp.data b/src/ext_depends/D-YAML/test/data/construct-timestamp.data new file mode 100644 index 0000000..840273b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-timestamp.data @@ -0,0 +1,5 @@ +canonical: 2001-12-15T02:59:43.1Z +valid iso8601: 2001-12-14t21:59:43.1-05:00 +space separated: 2001-12-14 21:59:43.1 -5 +no time zone (Z): 2001-12-15 2:59:43.1 +date (00:00:00Z): 2002-12-14 diff --git a/src/ext_depends/D-YAML/test/data/construct-value.code b/src/ext_depends/D-YAML/test/data/construct-value.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-value.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/construct-value.data b/src/ext_depends/D-YAML/test/data/construct-value.data new file mode 100644 index 0000000..3eb7919 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/construct-value.data @@ -0,0 +1,10 @@ +--- # Old schema +link with: + - library1.dll + - library2.dll +--- # New schema +link with: + - = : library1.dll + version: 1.2 + - = : library2.dll + version: 2.3 diff --git a/src/ext_depends/D-YAML/test/data/document-separator-in-quoted-scalar.loader-error b/src/ext_depends/D-YAML/test/data/document-separator-in-quoted-scalar.loader-error new file mode 100644 index 0000000..9eeb0d6 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/document-separator-in-quoted-scalar.loader-error @@ -0,0 +1,11 @@ +--- +"this --- is correct" +--- +"this +...is also +correct" +--- +"a quoted scalar +cannot contain +--- +document separators" diff --git a/src/ext_depends/D-YAML/test/data/documents.events b/src/ext_depends/D-YAML/test/data/documents.events new file mode 100644 index 0000000..775a51a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/documents.events @@ -0,0 +1,11 @@ +- !StreamStart +- !DocumentStart { explicit: false } +- !Scalar { implicit: [true,false], value: 'data' } +- !DocumentEnd +- !DocumentStart +- !Scalar { implicit: [true,false] } +- !DocumentEnd +- !DocumentStart { version: [1,1], tags: { '!': '!foo', '!yaml!': 'tag:yaml.org,2002:', '!ugly!': '!!!!!!!' } } +- !Scalar { implicit: [true,false] } +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/duplicate-anchor-1.loader-error b/src/ext_depends/D-YAML/test/data/duplicate-anchor-1.loader-error new file mode 100644 index 0000000..906cf29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/duplicate-anchor-1.loader-error @@ -0,0 +1,3 @@ +- &foo bar +- &bar bar +- &foo bar diff --git a/src/ext_depends/D-YAML/test/data/duplicate-anchor-2.loader-error b/src/ext_depends/D-YAML/test/data/duplicate-anchor-2.loader-error new file mode 100644 index 0000000..62b4389 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/duplicate-anchor-2.loader-error @@ -0,0 +1 @@ +&foo [1, 2, 3, &foo 4] diff --git a/src/ext_depends/D-YAML/test/data/duplicate-mapping-key.loader-error b/src/ext_depends/D-YAML/test/data/duplicate-mapping-key.loader-error new file mode 100644 index 0000000..55bce77 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/duplicate-mapping-key.loader-error @@ -0,0 +1,2 @@ +a: 1 +a: 2
\ No newline at end of file diff --git a/src/ext_depends/D-YAML/test/data/duplicate-merge-key.code b/src/ext_depends/D-YAML/test/data/duplicate-merge-key.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/duplicate-merge-key.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/duplicate-merge-key.data b/src/ext_depends/D-YAML/test/data/duplicate-merge-key.data new file mode 100644 index 0000000..cebc3a1 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/duplicate-merge-key.data @@ -0,0 +1,4 @@ +--- +<<: {x: 1, y: 2} +foo: bar +<<: {z: 3, t: 4} diff --git a/src/ext_depends/D-YAML/test/data/duplicate-tag-directive.loader-error b/src/ext_depends/D-YAML/test/data/duplicate-tag-directive.loader-error new file mode 100644 index 0000000..50c81a0 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/duplicate-tag-directive.loader-error @@ -0,0 +1,3 @@ +%TAG !foo! bar +%TAG !foo! baz +--- foo diff --git a/src/ext_depends/D-YAML/test/data/duplicate-yaml-directive.loader-error b/src/ext_depends/D-YAML/test/data/duplicate-yaml-directive.loader-error new file mode 100644 index 0000000..9b72390 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/duplicate-yaml-directive.loader-error @@ -0,0 +1,3 @@ +%YAML 1.1 +%YAML 1.1 +--- foo diff --git a/src/ext_depends/D-YAML/test/data/emit-block-scalar-in-simple-key-context-bug.canonical b/src/ext_depends/D-YAML/test/data/emit-block-scalar-in-simple-key-context-bug.canonical new file mode 100644 index 0000000..473bed5 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/emit-block-scalar-in-simple-key-context-bug.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- !!map +{ + ? !!str "foo" + : !!str "bar" +} diff --git a/src/ext_depends/D-YAML/test/data/emit-block-scalar-in-simple-key-context-bug.data b/src/ext_depends/D-YAML/test/data/emit-block-scalar-in-simple-key-context-bug.data new file mode 100644 index 0000000..b6b42ba --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/emit-block-scalar-in-simple-key-context-bug.data @@ -0,0 +1,4 @@ +? |- + foo +: |- + bar diff --git a/src/ext_depends/D-YAML/test/data/empty-anchor.emitter-error b/src/ext_depends/D-YAML/test/data/empty-anchor.emitter-error new file mode 100644 index 0000000..ce663b6 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/empty-anchor.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart +- !Scalar { anchor: '', value: 'foo' } +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/empty-document-bug.canonical b/src/ext_depends/D-YAML/test/data/empty-document-bug.canonical new file mode 100644 index 0000000..28a6cf1 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/empty-document-bug.canonical @@ -0,0 +1 @@ +# This YAML stream contains no YAML documents. diff --git a/src/ext_depends/D-YAML/test/data/empty-document-bug.data b/src/ext_depends/D-YAML/test/data/empty-document-bug.data new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/empty-document-bug.data diff --git a/src/ext_depends/D-YAML/test/data/empty-document-bug.empty b/src/ext_depends/D-YAML/test/data/empty-document-bug.empty new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/empty-document-bug.empty diff --git a/src/ext_depends/D-YAML/test/data/empty-documents.single-loader-error b/src/ext_depends/D-YAML/test/data/empty-documents.single-loader-error new file mode 100644 index 0000000..f8dba8d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/empty-documents.single-loader-error @@ -0,0 +1,2 @@ +--- # first document +--- # second document diff --git a/src/ext_depends/D-YAML/test/data/empty-tag-handle.emitter-error b/src/ext_depends/D-YAML/test/data/empty-tag-handle.emitter-error new file mode 100644 index 0000000..235c899 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/empty-tag-handle.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart { tags: { '': 'bar' } } +- !Scalar { value: 'foo' } +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/empty-tag-prefix.emitter-error b/src/ext_depends/D-YAML/test/data/empty-tag-prefix.emitter-error new file mode 100644 index 0000000..c6c0e95 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/empty-tag-prefix.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart { tags: { '!': '' } } +- !Scalar { value: 'foo' } +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/empty-tag.emitter-error b/src/ext_depends/D-YAML/test/data/empty-tag.emitter-error new file mode 100644 index 0000000..b7ca593 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/empty-tag.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart +- !Scalar { tag: '', value: 'key', implicit: [false,false] } +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/expected-document-end.emitter-error b/src/ext_depends/D-YAML/test/data/expected-document-end.emitter-error new file mode 100644 index 0000000..0cbab89 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/expected-document-end.emitter-error @@ -0,0 +1,6 @@ +- !StreamStart +- !DocumentStart +- !Scalar { value: 'data 1' } +- !Scalar { value: 'data 2' } +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/expected-document-start.emitter-error b/src/ext_depends/D-YAML/test/data/expected-document-start.emitter-error new file mode 100644 index 0000000..8ce575e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/expected-document-start.emitter-error @@ -0,0 +1,4 @@ +- !StreamStart +- !MappingStart +- !MappingEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/expected-mapping.loader-error b/src/ext_depends/D-YAML/test/data/expected-mapping.loader-error new file mode 100644 index 0000000..82aed98 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/expected-mapping.loader-error @@ -0,0 +1 @@ +--- !!map [not, a, map] diff --git a/src/ext_depends/D-YAML/test/data/expected-node-1.emitter-error b/src/ext_depends/D-YAML/test/data/expected-node-1.emitter-error new file mode 100644 index 0000000..36ceca3 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/expected-node-1.emitter-error @@ -0,0 +1,4 @@ +- !StreamStart +- !DocumentStart +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/expected-node-2.emitter-error b/src/ext_depends/D-YAML/test/data/expected-node-2.emitter-error new file mode 100644 index 0000000..891ee37 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/expected-node-2.emitter-error @@ -0,0 +1,7 @@ +- !StreamStart +- !DocumentStart +- !MappingStart +- !Scalar { value: 'key' } +- !MappingEnd +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/expected-nothing.emitter-error b/src/ext_depends/D-YAML/test/data/expected-nothing.emitter-error new file mode 100644 index 0000000..62c54d3 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/expected-nothing.emitter-error @@ -0,0 +1,4 @@ +- !StreamStart +- !StreamEnd +- !StreamStart +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/expected-scalar.loader-error b/src/ext_depends/D-YAML/test/data/expected-scalar.loader-error new file mode 100644 index 0000000..7b3171e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/expected-scalar.loader-error @@ -0,0 +1 @@ +--- !!str [not a scalar] diff --git a/src/ext_depends/D-YAML/test/data/expected-sequence.loader-error b/src/ext_depends/D-YAML/test/data/expected-sequence.loader-error new file mode 100644 index 0000000..08074ea --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/expected-sequence.loader-error @@ -0,0 +1 @@ +--- !!seq {foo, bar, baz} diff --git a/src/ext_depends/D-YAML/test/data/expected-stream-start.emitter-error b/src/ext_depends/D-YAML/test/data/expected-stream-start.emitter-error new file mode 100644 index 0000000..480dc2e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/expected-stream-start.emitter-error @@ -0,0 +1,2 @@ +- !DocumentStart +- !DocumentEnd diff --git a/src/ext_depends/D-YAML/test/data/explicit-document.single-loader-error b/src/ext_depends/D-YAML/test/data/explicit-document.single-loader-error new file mode 100644 index 0000000..46c6f8b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/explicit-document.single-loader-error @@ -0,0 +1,4 @@ +--- +foo: bar +--- +foo: bar diff --git a/src/ext_depends/D-YAML/test/data/fetch-complex-value-bug.loader-error b/src/ext_depends/D-YAML/test/data/fetch-complex-value-bug.loader-error new file mode 100644 index 0000000..25fac24 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/fetch-complex-value-bug.loader-error @@ -0,0 +1,2 @@ +? "foo" + : "bar" diff --git a/src/ext_depends/D-YAML/test/data/float-representer-2.3-bug.code b/src/ext_depends/D-YAML/test/data/float-representer-2.3-bug.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/float-representer-2.3-bug.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/float-representer-2.3-bug.data b/src/ext_depends/D-YAML/test/data/float-representer-2.3-bug.data new file mode 100644 index 0000000..efd1716 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/float-representer-2.3-bug.data @@ -0,0 +1,5 @@ +#0.0: # hash(0) == hash(nan) and 0 == nan in Python 2.3 +1.0: 1 ++.inf: 10 +-.inf: -10 +.nan: 100 diff --git a/src/ext_depends/D-YAML/test/data/float.data b/src/ext_depends/D-YAML/test/data/float.data new file mode 100644 index 0000000..524d5db --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/float.data @@ -0,0 +1,6 @@ +- 6.8523015e+5 +- 685.230_15e+03 +- 685_230.15 +- 190:20:30.15 +- -.inf +- .NaN diff --git a/src/ext_depends/D-YAML/test/data/float.detect b/src/ext_depends/D-YAML/test/data/float.detect new file mode 100644 index 0000000..1e12343 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/float.detect @@ -0,0 +1 @@ +tag:yaml.org,2002:float diff --git a/src/ext_depends/D-YAML/test/data/forbidden-entry.loader-error b/src/ext_depends/D-YAML/test/data/forbidden-entry.loader-error new file mode 100644 index 0000000..f2e3079 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/forbidden-entry.loader-error @@ -0,0 +1,2 @@ +test: - foo + - bar diff --git a/src/ext_depends/D-YAML/test/data/forbidden-key.loader-error b/src/ext_depends/D-YAML/test/data/forbidden-key.loader-error new file mode 100644 index 0000000..da9b471 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/forbidden-key.loader-error @@ -0,0 +1,2 @@ +test: ? foo + : bar diff --git a/src/ext_depends/D-YAML/test/data/forbidden-value.loader-error b/src/ext_depends/D-YAML/test/data/forbidden-value.loader-error new file mode 100644 index 0000000..efd7ce5 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/forbidden-value.loader-error @@ -0,0 +1 @@ +test: key: value diff --git a/src/ext_depends/D-YAML/test/data/implicit-document.single-loader-error b/src/ext_depends/D-YAML/test/data/implicit-document.single-loader-error new file mode 100644 index 0000000..f8c9a5c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/implicit-document.single-loader-error @@ -0,0 +1,3 @@ +foo: bar +--- +foo: bar diff --git a/src/ext_depends/D-YAML/test/data/int.data b/src/ext_depends/D-YAML/test/data/int.data new file mode 100644 index 0000000..d44d376 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/int.data @@ -0,0 +1,6 @@ +- 685230 +- +685_230 +- 02472256 +- 0x_0A_74_AE +- 0b1010_0111_0100_1010_1110 +- 190:20:30 diff --git a/src/ext_depends/D-YAML/test/data/int.detect b/src/ext_depends/D-YAML/test/data/int.detect new file mode 100644 index 0000000..575c9eb --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/int.detect @@ -0,0 +1 @@ +tag:yaml.org,2002:int diff --git a/src/ext_depends/D-YAML/test/data/invalid-anchor-1.loader-error b/src/ext_depends/D-YAML/test/data/invalid-anchor-1.loader-error new file mode 100644 index 0000000..fcf7d0f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-anchor-1.loader-error @@ -0,0 +1 @@ +--- &? foo # we allow only ascii and numeric characters in anchor names. diff --git a/src/ext_depends/D-YAML/test/data/invalid-anchor-2.loader-error b/src/ext_depends/D-YAML/test/data/invalid-anchor-2.loader-error new file mode 100644 index 0000000..bfc4ff0 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-anchor-2.loader-error @@ -0,0 +1,8 @@ +--- +- [ + &correct foo, + *correct, + *correct] # still correct +- *correct: still correct +- &correct-or-not[foo, bar] + diff --git a/src/ext_depends/D-YAML/test/data/invalid-anchor.emitter-error b/src/ext_depends/D-YAML/test/data/invalid-anchor.emitter-error new file mode 100644 index 0000000..3d2a814 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-anchor.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart +- !Scalar { anchor: '5*5=25', value: 'foo' } +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/invalid-base64-data-2.loader-error b/src/ext_depends/D-YAML/test/data/invalid-base64-data-2.loader-error new file mode 100644 index 0000000..2553a4f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-base64-data-2.loader-error @@ -0,0 +1,2 @@ +--- !!binary + двоичные данные в base64 diff --git a/src/ext_depends/D-YAML/test/data/invalid-base64-data.loader-error b/src/ext_depends/D-YAML/test/data/invalid-base64-data.loader-error new file mode 100644 index 0000000..798abba --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-base64-data.loader-error @@ -0,0 +1,2 @@ +--- !!binary + binary data encoded in base64 should be here. diff --git a/src/ext_depends/D-YAML/test/data/invalid-block-scalar-indicator.loader-error b/src/ext_depends/D-YAML/test/data/invalid-block-scalar-indicator.loader-error new file mode 100644 index 0000000..16a6db1 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-block-scalar-indicator.loader-error @@ -0,0 +1,2 @@ +--- > what is this? # a comment +data diff --git a/src/ext_depends/D-YAML/test/data/invalid-character.loader-error b/src/ext_depends/D-YAML/test/data/invalid-character.loader-error Binary files differnew file mode 100644 index 0000000..03687b0 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-character.loader-error diff --git a/src/ext_depends/D-YAML/test/data/invalid-character.stream-error b/src/ext_depends/D-YAML/test/data/invalid-character.stream-error Binary files differnew file mode 100644 index 0000000..171face --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-character.stream-error diff --git a/src/ext_depends/D-YAML/test/data/invalid-directive-line.loader-error b/src/ext_depends/D-YAML/test/data/invalid-directive-line.loader-error new file mode 100644 index 0000000..0892eb6 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-directive-line.loader-error @@ -0,0 +1,2 @@ +%YAML 1.1 ? # extra symbol +--- diff --git a/src/ext_depends/D-YAML/test/data/invalid-directive-name-1.loader-error b/src/ext_depends/D-YAML/test/data/invalid-directive-name-1.loader-error new file mode 100644 index 0000000..153fd88 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-directive-name-1.loader-error @@ -0,0 +1,2 @@ +% # no name at all +--- diff --git a/src/ext_depends/D-YAML/test/data/invalid-directive-name-2.loader-error b/src/ext_depends/D-YAML/test/data/invalid-directive-name-2.loader-error new file mode 100644 index 0000000..3732a06 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-directive-name-2.loader-error @@ -0,0 +1,2 @@ +%invalid-characters:in-directive name +--- diff --git a/src/ext_depends/D-YAML/test/data/invalid-escape-character.loader-error b/src/ext_depends/D-YAML/test/data/invalid-escape-character.loader-error new file mode 100644 index 0000000..a95ab76 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-escape-character.loader-error @@ -0,0 +1 @@ +"some escape characters are \ncorrect, but this one \?\nis not\n" diff --git a/src/ext_depends/D-YAML/test/data/invalid-escape-numbers.loader-error b/src/ext_depends/D-YAML/test/data/invalid-escape-numbers.loader-error new file mode 100644 index 0000000..614ec9f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-escape-numbers.loader-error @@ -0,0 +1 @@ +"hm.... \u123?" diff --git a/src/ext_depends/D-YAML/test/data/invalid-indentation-indicator-1.loader-error b/src/ext_depends/D-YAML/test/data/invalid-indentation-indicator-1.loader-error new file mode 100644 index 0000000..a3cd12f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-indentation-indicator-1.loader-error @@ -0,0 +1,2 @@ +--- >0 # not valid +data diff --git a/src/ext_depends/D-YAML/test/data/invalid-indentation-indicator-2.loader-error b/src/ext_depends/D-YAML/test/data/invalid-indentation-indicator-2.loader-error new file mode 100644 index 0000000..eefb6ec --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-indentation-indicator-2.loader-error @@ -0,0 +1,2 @@ +--- >-0 +data diff --git a/src/ext_depends/D-YAML/test/data/invalid-item-without-trailing-break.loader-error b/src/ext_depends/D-YAML/test/data/invalid-item-without-trailing-break.loader-error new file mode 100644 index 0000000..fdcf6c6 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-item-without-trailing-break.loader-error @@ -0,0 +1,2 @@ +- +-0
\ No newline at end of file diff --git a/src/ext_depends/D-YAML/test/data/invalid-merge-1.loader-error b/src/ext_depends/D-YAML/test/data/invalid-merge-1.loader-error new file mode 100644 index 0000000..fc3c284 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-merge-1.loader-error @@ -0,0 +1,2 @@ +foo: bar +<<: baz diff --git a/src/ext_depends/D-YAML/test/data/invalid-merge-2.loader-error b/src/ext_depends/D-YAML/test/data/invalid-merge-2.loader-error new file mode 100644 index 0000000..8e88615 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-merge-2.loader-error @@ -0,0 +1,2 @@ +foo: bar +<<: [x: 1, y: 2, z, t: 4] diff --git a/src/ext_depends/D-YAML/test/data/invalid-omap-1.loader-error b/src/ext_depends/D-YAML/test/data/invalid-omap-1.loader-error new file mode 100644 index 0000000..2863392 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-omap-1.loader-error @@ -0,0 +1,3 @@ +--- !!omap +foo: bar +baz: bat diff --git a/src/ext_depends/D-YAML/test/data/invalid-omap-2.loader-error b/src/ext_depends/D-YAML/test/data/invalid-omap-2.loader-error new file mode 100644 index 0000000..c377dfb --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-omap-2.loader-error @@ -0,0 +1,3 @@ +--- !!omap +- foo: bar +- baz diff --git a/src/ext_depends/D-YAML/test/data/invalid-omap-3.loader-error b/src/ext_depends/D-YAML/test/data/invalid-omap-3.loader-error new file mode 100644 index 0000000..2a4f50d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-omap-3.loader-error @@ -0,0 +1,4 @@ +--- !!omap +- foo: bar +- baz: bar + bar: bar diff --git a/src/ext_depends/D-YAML/test/data/invalid-pairs-1.loader-error b/src/ext_depends/D-YAML/test/data/invalid-pairs-1.loader-error new file mode 100644 index 0000000..42d19ae --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-pairs-1.loader-error @@ -0,0 +1,3 @@ +--- !!pairs +foo: bar +baz: bat diff --git a/src/ext_depends/D-YAML/test/data/invalid-pairs-2.loader-error b/src/ext_depends/D-YAML/test/data/invalid-pairs-2.loader-error new file mode 100644 index 0000000..31389ea --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-pairs-2.loader-error @@ -0,0 +1,3 @@ +--- !!pairs +- foo: bar +- baz diff --git a/src/ext_depends/D-YAML/test/data/invalid-pairs-3.loader-error b/src/ext_depends/D-YAML/test/data/invalid-pairs-3.loader-error new file mode 100644 index 0000000..f8d7704 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-pairs-3.loader-error @@ -0,0 +1,4 @@ +--- !!pairs +- foo: bar +- baz: bar + bar: bar diff --git a/src/ext_depends/D-YAML/test/data/invalid-simple-key.loader-error b/src/ext_depends/D-YAML/test/data/invalid-simple-key.loader-error new file mode 100644 index 0000000..a58deec --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-simple-key.loader-error @@ -0,0 +1,3 @@ +key: value +invalid simple key +next key: next value diff --git a/src/ext_depends/D-YAML/test/data/invalid-single-quote-bug.code b/src/ext_depends/D-YAML/test/data/invalid-single-quote-bug.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-single-quote-bug.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/invalid-single-quote-bug.data b/src/ext_depends/D-YAML/test/data/invalid-single-quote-bug.data new file mode 100644 index 0000000..76ef7ae --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-single-quote-bug.data @@ -0,0 +1,2 @@ +- "foo 'bar'" +- "foo\n'bar'" diff --git a/src/ext_depends/D-YAML/test/data/invalid-starting-character.loader-error b/src/ext_depends/D-YAML/test/data/invalid-starting-character.loader-error new file mode 100644 index 0000000..bb81c60 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-starting-character.loader-error @@ -0,0 +1 @@ +@@@@@@@@@@@@@@@@@@@ diff --git a/src/ext_depends/D-YAML/test/data/invalid-tag-1.loader-error b/src/ext_depends/D-YAML/test/data/invalid-tag-1.loader-error new file mode 100644 index 0000000..a68cd38 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-tag-1.loader-error @@ -0,0 +1 @@ +- !<foo#bar> baz diff --git a/src/ext_depends/D-YAML/test/data/invalid-tag-2.loader-error b/src/ext_depends/D-YAML/test/data/invalid-tag-2.loader-error new file mode 100644 index 0000000..3a36700 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-tag-2.loader-error @@ -0,0 +1 @@ +- !prefix!foo#bar baz diff --git a/src/ext_depends/D-YAML/test/data/invalid-tag-directive-handle.loader-error b/src/ext_depends/D-YAML/test/data/invalid-tag-directive-handle.loader-error new file mode 100644 index 0000000..42b5d7e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-tag-directive-handle.loader-error @@ -0,0 +1,2 @@ +%TAG !!! !!! +--- diff --git a/src/ext_depends/D-YAML/test/data/invalid-tag-directive-prefix.loader-error b/src/ext_depends/D-YAML/test/data/invalid-tag-directive-prefix.loader-error new file mode 100644 index 0000000..0cb482c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-tag-directive-prefix.loader-error @@ -0,0 +1,2 @@ +%TAG ! tag:zz.com/foo#bar # '#' is not allowed in URLs +--- diff --git a/src/ext_depends/D-YAML/test/data/invalid-tag-handle-1.emitter-error b/src/ext_depends/D-YAML/test/data/invalid-tag-handle-1.emitter-error new file mode 100644 index 0000000..d5df9a2 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-tag-handle-1.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart { tags: { '!foo': 'bar' } } +- !Scalar { value: 'foo' } +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/invalid-tag-handle-1.loader-error b/src/ext_depends/D-YAML/test/data/invalid-tag-handle-1.loader-error new file mode 100644 index 0000000..ef0d143 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-tag-handle-1.loader-error @@ -0,0 +1,2 @@ +%TAG foo bar +--- diff --git a/src/ext_depends/D-YAML/test/data/invalid-tag-handle-2.emitter-error b/src/ext_depends/D-YAML/test/data/invalid-tag-handle-2.emitter-error new file mode 100644 index 0000000..d1831d5 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-tag-handle-2.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart { tags: { '!!!': 'bar' } } +- !Scalar { value: 'foo' } +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/invalid-tag-handle-2.loader-error b/src/ext_depends/D-YAML/test/data/invalid-tag-handle-2.loader-error new file mode 100644 index 0000000..06c7f0e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-tag-handle-2.loader-error @@ -0,0 +1,2 @@ +%TAG !foo bar +--- diff --git a/src/ext_depends/D-YAML/test/data/invalid-uri-escapes-1.loader-error b/src/ext_depends/D-YAML/test/data/invalid-uri-escapes-1.loader-error new file mode 100644 index 0000000..a6ecb36 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-uri-escapes-1.loader-error @@ -0,0 +1 @@ +--- !<tag:%x?y> foo diff --git a/src/ext_depends/D-YAML/test/data/invalid-uri-escapes-2.loader-error b/src/ext_depends/D-YAML/test/data/invalid-uri-escapes-2.loader-error new file mode 100644 index 0000000..b89e8f6 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-uri-escapes-2.loader-error @@ -0,0 +1 @@ +--- !<%FF> foo diff --git a/src/ext_depends/D-YAML/test/data/invalid-uri-escapes-3.loader-error b/src/ext_depends/D-YAML/test/data/invalid-uri-escapes-3.loader-error new file mode 100644 index 0000000..f2e4cb8 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-uri-escapes-3.loader-error @@ -0,0 +1 @@ +--- !<foo%d0%af%d0%af%d0bar> baz diff --git a/src/ext_depends/D-YAML/test/data/invalid-uri.loader-error b/src/ext_depends/D-YAML/test/data/invalid-uri.loader-error new file mode 100644 index 0000000..06307e0 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-uri.loader-error @@ -0,0 +1 @@ +--- !foo! bar diff --git a/src/ext_depends/D-YAML/test/data/invalid-utf8-byte.loader-error b/src/ext_depends/D-YAML/test/data/invalid-utf8-byte.loader-error new file mode 100644 index 0000000..0a58c70 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-utf8-byte.loader-error @@ -0,0 +1,66 @@ +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +Invalid byte ('\xFF'): <-- +############################################################### diff --git a/src/ext_depends/D-YAML/test/data/invalid-utf8-byte.stream-error b/src/ext_depends/D-YAML/test/data/invalid-utf8-byte.stream-error new file mode 100644 index 0000000..0a58c70 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-utf8-byte.stream-error @@ -0,0 +1,66 @@ +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +############################################################### +Invalid byte ('\xFF'): <-- +############################################################### diff --git a/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-1.loader-error b/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-1.loader-error new file mode 100644 index 0000000..e9b4e3a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-1.loader-error @@ -0,0 +1,3 @@ +# No version at all. +%YAML +--- diff --git a/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-2.loader-error b/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-2.loader-error new file mode 100644 index 0000000..6aa7740 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-2.loader-error @@ -0,0 +1,2 @@ +%YAML 1e-5 +--- diff --git a/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-3.loader-error b/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-3.loader-error new file mode 100644 index 0000000..345e784 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-3.loader-error @@ -0,0 +1,2 @@ +%YAML 1. +--- diff --git a/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-4.loader-error b/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-4.loader-error new file mode 100644 index 0000000..b35ca82 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-4.loader-error @@ -0,0 +1,2 @@ +%YAML 1.132.435 +--- diff --git a/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-5.loader-error b/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-5.loader-error new file mode 100644 index 0000000..7c2b49f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-5.loader-error @@ -0,0 +1,2 @@ +%YAML A.0 +--- diff --git a/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-6.loader-error b/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-6.loader-error new file mode 100644 index 0000000..bae714f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-yaml-directive-version-6.loader-error @@ -0,0 +1,2 @@ +%YAML 123.C +--- diff --git a/src/ext_depends/D-YAML/test/data/invalid-yaml-version.loader-error b/src/ext_depends/D-YAML/test/data/invalid-yaml-version.loader-error new file mode 100644 index 0000000..dd01948 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/invalid-yaml-version.loader-error @@ -0,0 +1,2 @@ +%YAML 2.0 +--- foo diff --git a/src/ext_depends/D-YAML/test/data/latin.unicode b/src/ext_depends/D-YAML/test/data/latin.unicode new file mode 100644 index 0000000..4fb799c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/latin.unicode @@ -0,0 +1,384 @@ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµºÀÁÂÃÄÅÆÇÈÉÊ +ËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎ +ďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐ +őŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒ +ƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƼƽƾƿDŽdžLJljNJnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜ +ǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ +ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯ +ɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΆΈ +ΉΊΌΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύ +ώϐϑϒϓϔϕϖϗϘϙϚϛϜϝϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰϱϲϳϴϵϷϸϹϺϻϼϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБ +ВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓ +єѕіїјљњћќѝўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁҊҋҌҍҎҏҐґҒғҔҕҖҗҘҙҚқҜҝ +ҞҟҠҡҢңҤҥҦҧҨҩҪҫҬҭҮүҰұҲҳҴҵҶҷҸҹҺһҼҽҾҿӀӁӂӃӄӅӆӇӈӉӊӋӌӍӎӐӑӒӓӔӕӖӗӘәӚӛӜӝӞӟӠ +ӡӢӣӤӥӦӧӨөӪӫӬӭӮӯӰӱӲӳӴӵӶӷӸӹԀԁԂԃԄԅԆԇԈԉԊԋԌԍԎԏԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉ +ՊՋՌՍՎՏՐՑՒՓՔՕՖաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևႠႡႢႣႤႥႦႧႨႩႪႫႬႭ +ႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩ +ᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḀḁḂḃḄḅḆḇ +ḈḉḊḋḌḍḎḏḐḑḒḓḔḕḖḗḘḙḚḛḜḝḞḟḠḡḢḣḤḥḦḧḨḩḪḫḬḭḮḯḰḱḲḳḴḵḶḷḸḹḺḻḼḽḾḿṀṁṂṃṄṅṆṇṈṉ +ṊṋṌṍṎṏṐṑṒṓṔṕṖṗṘṙṚṛṜṝṞṟṠṡṢṣṤṥṦṧṨṩṪṫṬṭṮṯṰṱṲṳṴṵṶṷṸṹṺṻṼṽṾṿẀẁẂẃẄẅẆẇẈẉẊẋ +ẌẍẎẏẐẑẒẓẔẕẖẗẘẙẚẛẠạẢảẤấẦầẨẩẪẫẬậẮắẰằẲẳẴẵẶặẸẹẺẻẼẽẾếỀềỂểỄễỆệỈỉỊịỌọỎỏỐố +ỒồỔổỖỗỘộỚớỜờỞởỠỡỢợỤụỦủỨứỪừỬửỮữỰựỲỳỴỵỶỷỸỹἀἁἂἃἄἅἆἇἈἉἊἋἌἍἎἏἐἑἒἓἔἕἘἙἚἛ +ἜἝἠἡἢἣἤἥἦἧἨἩἪἫἬἭἮἯἰἱἲἳἴἵἶἷἸἹἺἻἼἽἾἿὀὁὂὃὄὅὈὉὊὋὌὍὐὑὒὓὔὕὖὗὙὛὝὟὠὡὢὣὤὥὦὧ +ὨὩὪὫὬὭὮὯὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷᾸᾹᾺΆιῂῃῄῆῇῈΈῊ +ΉῐῑῒΐῖῗῘῙῚΊῠῡῢΰῤῥῦῧῨῩῪΎῬῲῳῴῶῷῸΌῺΏⁱⁿℂℇℊℋℌℍℎℏℐℑℒℓℕℙℚℛℜℝℤΩℨKÅℬℭℯℰℱℳℴℹ diff --git a/src/ext_depends/D-YAML/test/data/mappings.events b/src/ext_depends/D-YAML/test/data/mappings.events new file mode 100644 index 0000000..3cb5579 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/mappings.events @@ -0,0 +1,44 @@ +- !StreamStart + +- !DocumentStart +- !MappingStart +- !Scalar { implicit: [true,true], value: 'key' } +- !Scalar { implicit: [true,true], value: 'value' } +- !Scalar { implicit: [true,true], value: 'empty mapping' } +- !MappingStart +- !MappingEnd +- !Scalar { implicit: [true,true], value: 'empty mapping with tag' } +- !MappingStart { tag: '!mytag', implicit: false } +- !MappingEnd +- !Scalar { implicit: [true,true], value: 'block mapping' } +- !MappingStart +- !MappingStart +- !Scalar { implicit: [true,true], value: 'complex' } +- !Scalar { implicit: [true,true], value: 'key' } +- !Scalar { implicit: [true,true], value: 'complex' } +- !Scalar { implicit: [true,true], value: 'key' } +- !MappingEnd +- !MappingStart +- !Scalar { implicit: [true,true], value: 'complex' } +- !Scalar { implicit: [true,true], value: 'key' } +- !MappingEnd +- !MappingEnd +- !Scalar { implicit: [true,true], value: 'flow mapping' } +- !MappingStart { flow_style: true } +- !Scalar { implicit: [true,true], value: 'key' } +- !Scalar { implicit: [true,true], value: 'value' } +- !MappingStart +- !Scalar { implicit: [true,true], value: 'complex' } +- !Scalar { implicit: [true,true], value: 'key' } +- !Scalar { implicit: [true,true], value: 'complex' } +- !Scalar { implicit: [true,true], value: 'key' } +- !MappingEnd +- !MappingStart +- !Scalar { implicit: [true,true], value: 'complex' } +- !Scalar { implicit: [true,true], value: 'key' } +- !MappingEnd +- !MappingEnd +- !MappingEnd +- !DocumentEnd + +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/merge.data b/src/ext_depends/D-YAML/test/data/merge.data new file mode 100644 index 0000000..e455bbc --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/merge.data @@ -0,0 +1 @@ +- << diff --git a/src/ext_depends/D-YAML/test/data/merge.detect b/src/ext_depends/D-YAML/test/data/merge.detect new file mode 100644 index 0000000..1672d0d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/merge.detect @@ -0,0 +1 @@ +tag:yaml.org,2002:merge diff --git a/src/ext_depends/D-YAML/test/data/more-floats.code b/src/ext_depends/D-YAML/test/data/more-floats.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/more-floats.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/more-floats.data b/src/ext_depends/D-YAML/test/data/more-floats.data new file mode 100644 index 0000000..399eb17 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/more-floats.data @@ -0,0 +1 @@ +[0.0, +1.0, -1.0, +.inf, -.inf, .nan, .nan] diff --git a/src/ext_depends/D-YAML/test/data/negative-float-bug.code b/src/ext_depends/D-YAML/test/data/negative-float-bug.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/negative-float-bug.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/negative-float-bug.data b/src/ext_depends/D-YAML/test/data/negative-float-bug.data new file mode 100644 index 0000000..18e16e3 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/negative-float-bug.data @@ -0,0 +1 @@ +-1.0 diff --git a/src/ext_depends/D-YAML/test/data/no-alias-anchor.emitter-error b/src/ext_depends/D-YAML/test/data/no-alias-anchor.emitter-error new file mode 100644 index 0000000..5ff065c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/no-alias-anchor.emitter-error @@ -0,0 +1,8 @@ +- !StreamStart +- !DocumentStart +- !SequenceStart +- !Scalar { anchor: A, value: data } +- !Alias { } +- !SequenceEnd +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/no-alias-anchor.skip-ext b/src/ext_depends/D-YAML/test/data/no-alias-anchor.skip-ext new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/no-alias-anchor.skip-ext diff --git a/src/ext_depends/D-YAML/test/data/no-block-collection-end.loader-error b/src/ext_depends/D-YAML/test/data/no-block-collection-end.loader-error new file mode 100644 index 0000000..02d4d37 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/no-block-collection-end.loader-error @@ -0,0 +1,3 @@ +- foo +- bar +baz: bar diff --git a/src/ext_depends/D-YAML/test/data/no-block-mapping-end-2.loader-error b/src/ext_depends/D-YAML/test/data/no-block-mapping-end-2.loader-error new file mode 100644 index 0000000..be63571 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/no-block-mapping-end-2.loader-error @@ -0,0 +1,3 @@ +? foo +: bar +: baz diff --git a/src/ext_depends/D-YAML/test/data/no-block-mapping-end.loader-error b/src/ext_depends/D-YAML/test/data/no-block-mapping-end.loader-error new file mode 100644 index 0000000..1ea921c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/no-block-mapping-end.loader-error @@ -0,0 +1 @@ +foo: "bar" "baz" diff --git a/src/ext_depends/D-YAML/test/data/no-document-start.loader-error b/src/ext_depends/D-YAML/test/data/no-document-start.loader-error new file mode 100644 index 0000000..c725ec8 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/no-document-start.loader-error @@ -0,0 +1,3 @@ +%YAML 1.1 +# no --- +foo: bar diff --git a/src/ext_depends/D-YAML/test/data/no-flow-mapping-end.loader-error b/src/ext_depends/D-YAML/test/data/no-flow-mapping-end.loader-error new file mode 100644 index 0000000..8bd1403 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/no-flow-mapping-end.loader-error @@ -0,0 +1 @@ +{ foo: bar ] diff --git a/src/ext_depends/D-YAML/test/data/no-flow-sequence-end.loader-error b/src/ext_depends/D-YAML/test/data/no-flow-sequence-end.loader-error new file mode 100644 index 0000000..750d973 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/no-flow-sequence-end.loader-error @@ -0,0 +1 @@ +[foo, bar} diff --git a/src/ext_depends/D-YAML/test/data/no-node-1.loader-error b/src/ext_depends/D-YAML/test/data/no-node-1.loader-error new file mode 100644 index 0000000..07b1500 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/no-node-1.loader-error @@ -0,0 +1 @@ +- !foo ] diff --git a/src/ext_depends/D-YAML/test/data/no-node-2.loader-error b/src/ext_depends/D-YAML/test/data/no-node-2.loader-error new file mode 100644 index 0000000..563e3b3 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/no-node-2.loader-error @@ -0,0 +1 @@ +- [ !foo } ] diff --git a/src/ext_depends/D-YAML/test/data/no-tag.emitter-error b/src/ext_depends/D-YAML/test/data/no-tag.emitter-error new file mode 100644 index 0000000..384c62f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/no-tag.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart +- !Scalar { value: 'foo', implicit: [false,false] } +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/null.data b/src/ext_depends/D-YAML/test/data/null.data new file mode 100644 index 0000000..ad12528 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/null.data @@ -0,0 +1,3 @@ +- +- ~ +- null diff --git a/src/ext_depends/D-YAML/test/data/null.detect b/src/ext_depends/D-YAML/test/data/null.detect new file mode 100644 index 0000000..19110c7 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/null.detect @@ -0,0 +1 @@ +tag:yaml.org,2002:null diff --git a/src/ext_depends/D-YAML/test/data/odd-utf16.stream-error b/src/ext_depends/D-YAML/test/data/odd-utf16.stream-error Binary files differnew file mode 100644 index 0000000..b59e434 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/odd-utf16.stream-error diff --git a/src/ext_depends/D-YAML/test/data/recursive.former-dumper-error b/src/ext_depends/D-YAML/test/data/recursive.former-dumper-error new file mode 100644 index 0000000..3c7cc2f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/recursive.former-dumper-error @@ -0,0 +1,3 @@ +data = [] +data.append(data) +dump(data) diff --git a/src/ext_depends/D-YAML/test/data/remove-possible-simple-key-bug.loader-error b/src/ext_depends/D-YAML/test/data/remove-possible-simple-key-bug.loader-error new file mode 100644 index 0000000..fe1bc6c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/remove-possible-simple-key-bug.loader-error @@ -0,0 +1,3 @@ +foo: &A bar +*A ] # The ']' indicator triggers remove_possible_simple_key, + # which should raise an error. diff --git a/src/ext_depends/D-YAML/test/data/resolver.data b/src/ext_depends/D-YAML/test/data/resolver.data new file mode 100644 index 0000000..a296404 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/resolver.data @@ -0,0 +1,30 @@ +--- +"this scalar should be selected" +--- +key11: !foo + key12: + is: [selected] + key22: + key13: [not, selected] + key23: [not, selected] + key32: + key31: [not, selected] + key32: [not, selected] + key33: {not: selected} +key21: !bar + - not selected + - selected + - not selected +key31: !baz + key12: + key13: + key14: {selected} + key23: + key14: [not, selected] + key33: + key14: {selected} + key24: {not: selected} + key22: + - key14: {selected} + key24: {not: selected} + - key14: {selected} diff --git a/src/ext_depends/D-YAML/test/data/resolver.path b/src/ext_depends/D-YAML/test/data/resolver.path new file mode 100644 index 0000000..ec677d2 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/resolver.path @@ -0,0 +1,30 @@ +--- !root/scalar +"this scalar should be selected" +--- !root +key11: !foo + key12: !root/key11/key12/* + is: [selected] + key22: + key13: [not, selected] + key23: [not, selected] + key32: + key31: [not, selected] + key32: [not, selected] + key33: {not: selected} +key21: !bar + - not selected + - !root/key21/1/* selected + - not selected +key31: !baz + key12: + key13: + key14: !root/key31/*/*/key14/map {selected} + key23: + key14: [not, selected] + key33: + key14: !root/key31/*/*/key14/map {selected} + key24: {not: selected} + key22: + - key14: !root/key31/*/*/key14/map {selected} + key24: {not: selected} + - key14: !root/key31/*/*/key14/map {selected} diff --git a/src/ext_depends/D-YAML/test/data/run-parser-crash-bug.data b/src/ext_depends/D-YAML/test/data/run-parser-crash-bug.data new file mode 100644 index 0000000..fe01734 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/run-parser-crash-bug.data @@ -0,0 +1,8 @@ +--- +- Harry Potter and the Prisoner of Azkaban +- Harry Potter and the Goblet of Fire +- Harry Potter and the Order of the Phoenix +--- +- Memoirs Found in a Bathtub +- Snow Crash +- Ghost World diff --git a/src/ext_depends/D-YAML/test/data/scalars.events b/src/ext_depends/D-YAML/test/data/scalars.events new file mode 100644 index 0000000..32c40f4 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/scalars.events @@ -0,0 +1,28 @@ +- !StreamStart + +- !DocumentStart +- !MappingStart +- !Scalar { implicit: [true,true], value: 'empty scalar' } +- !Scalar { implicit: [true,false], value: '' } +- !Scalar { implicit: [true,true], value: 'implicit scalar' } +- !Scalar { implicit: [true,true], value: 'data' } +- !Scalar { implicit: [true,true], value: 'quoted scalar' } +- !Scalar { value: 'data', style: '"' } +- !Scalar { implicit: [true,true], value: 'block scalar' } +- !Scalar { value: 'data', style: '|' } +- !Scalar { implicit: [true,true], value: 'empty scalar with tag' } +- !Scalar { implicit: [false,false], tag: '!mytag', value: '' } +- !Scalar { implicit: [true,true], value: 'implicit scalar with tag' } +- !Scalar { implicit: [false,false], tag: '!mytag', value: 'data' } +- !Scalar { implicit: [true,true], value: 'quoted scalar with tag' } +- !Scalar { value: 'data', style: '"', tag: '!mytag', implicit: [false,false] } +- !Scalar { implicit: [true,true], value: 'block scalar with tag' } +- !Scalar { value: 'data', style: '|', tag: '!mytag', implicit: [false,false] } +- !Scalar { implicit: [true,true], value: 'single character' } +- !Scalar { value: 'a', implicit: [true,true] } +- !Scalar { implicit: [true,true], value: 'single digit' } +- !Scalar { value: '1', implicit: [true,false] } +- !MappingEnd +- !DocumentEnd + +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/scan-document-end-bug.canonical b/src/ext_depends/D-YAML/test/data/scan-document-end-bug.canonical new file mode 100644 index 0000000..4a0e8a8 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/scan-document-end-bug.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!null "" diff --git a/src/ext_depends/D-YAML/test/data/scan-document-end-bug.data b/src/ext_depends/D-YAML/test/data/scan-document-end-bug.data new file mode 100644 index 0000000..3c70543 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/scan-document-end-bug.data @@ -0,0 +1,3 @@ +# Ticket #4 +--- +...
\ No newline at end of file diff --git a/src/ext_depends/D-YAML/test/data/scan-line-break-bug.canonical b/src/ext_depends/D-YAML/test/data/scan-line-break-bug.canonical new file mode 100644 index 0000000..79f08b7 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/scan-line-break-bug.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!map { ? !!str "foo" : !!str "bar baz" } diff --git a/src/ext_depends/D-YAML/test/data/scan-line-break-bug.data b/src/ext_depends/D-YAML/test/data/scan-line-break-bug.data new file mode 100644 index 0000000..c974fab --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/scan-line-break-bug.data @@ -0,0 +1,3 @@ +foo:
+ bar
+ baz
diff --git a/src/ext_depends/D-YAML/test/data/sequences.events b/src/ext_depends/D-YAML/test/data/sequences.events new file mode 100644 index 0000000..692a329 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/sequences.events @@ -0,0 +1,81 @@ +- !StreamStart + +- !DocumentStart +- !SequenceStart +- !SequenceEnd +- !DocumentEnd + +- !DocumentStart +- !SequenceStart { tag: '!mytag', implicit: false } +- !SequenceEnd +- !DocumentEnd + +- !DocumentStart +- !SequenceStart +- !SequenceStart +- !SequenceEnd +- !SequenceStart { tag: '!mytag', implicit: false } +- !SequenceEnd +- !SequenceStart +- !Scalar +- !Scalar { value: 'data' } +- !Scalar { tag: '!mytag', implicit: [false,false], value: 'data' } +- !SequenceEnd +- !SequenceStart +- !SequenceStart +- !SequenceStart +- !Scalar +- !SequenceEnd +- !SequenceEnd +- !SequenceEnd +- !SequenceStart +- !SequenceStart { tag: '!mytag', implicit: false } +- !SequenceStart +- !Scalar { value: 'data' } +- !SequenceEnd +- !SequenceEnd +- !SequenceEnd +- !SequenceEnd +- !DocumentEnd + +- !DocumentStart +- !SequenceStart +- !MappingStart +- !Scalar { value: 'key1' } +- !SequenceStart +- !Scalar { value: 'data1' } +- !Scalar { value: 'data2' } +- !SequenceEnd +- !Scalar { value: 'key2' } +- !SequenceStart { tag: '!mytag1', implicit: false } +- !Scalar { value: 'data3' } +- !SequenceStart +- !Scalar { value: 'data4' } +- !Scalar { value: 'data5' } +- !SequenceEnd +- !SequenceStart { tag: '!mytag2', implicit: false } +- !Scalar { value: 'data6' } +- !Scalar { value: 'data7' } +- !SequenceEnd +- !SequenceEnd +- !MappingEnd +- !SequenceEnd +- !DocumentEnd + +- !DocumentStart +- !SequenceStart +- !SequenceStart { flow_style: true } +- !SequenceStart +- !SequenceEnd +- !Scalar +- !Scalar { value: 'data' } +- !Scalar { tag: '!mytag', implicit: [false,false], value: 'data' } +- !SequenceStart { tag: '!mytag', implicit: false } +- !Scalar { value: 'data' } +- !Scalar { value: 'data' } +- !SequenceEnd +- !SequenceEnd +- !SequenceEnd +- !DocumentEnd + +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/single-dot-is-not-float-bug.code b/src/ext_depends/D-YAML/test/data/single-dot-is-not-float-bug.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/single-dot-is-not-float-bug.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/single-dot-is-not-float-bug.data b/src/ext_depends/D-YAML/test/data/single-dot-is-not-float-bug.data new file mode 100644 index 0000000..9c558e3 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/single-dot-is-not-float-bug.data @@ -0,0 +1 @@ +. diff --git a/src/ext_depends/D-YAML/test/data/sloppy-indentation.canonical b/src/ext_depends/D-YAML/test/data/sloppy-indentation.canonical new file mode 100644 index 0000000..438bc04 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/sloppy-indentation.canonical @@ -0,0 +1,18 @@ +%YAML 1.1 +--- +!!map { + ? !!str "in the block context" + : !!map { + ? !!str "indentation should be kept" + : !!map { + ? !!str "but in the flow context" + : !!seq [ !!str "it may be violated" ] + } + } +} +--- !!str +"the parser does not require scalars to be indented with at least one space" +--- !!str +"the parser does not require scalars to be indented with at least one space" +--- !!map +{ ? !!str "foo": { ? !!str "bar" : !!str "quoted scalars may not adhere indentation" } } diff --git a/src/ext_depends/D-YAML/test/data/sloppy-indentation.data b/src/ext_depends/D-YAML/test/data/sloppy-indentation.data new file mode 100644 index 0000000..2eb4f5a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/sloppy-indentation.data @@ -0,0 +1,17 @@ +--- +in the block context: + indentation should be kept: { + but in the flow context: [ +it may be violated] +} +--- +the parser does not require scalars +to be indented with at least one space +... +--- +"the parser does not require scalars +to be indented with at least one space" +--- +foo: + bar: 'quoted scalars +may not adhere indentation' diff --git a/src/ext_depends/D-YAML/test/data/spec-02-01.data b/src/ext_depends/D-YAML/test/data/spec-02-01.data new file mode 100644 index 0000000..d12e671 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-01.data @@ -0,0 +1,3 @@ +- Mark McGwire +- Sammy Sosa +- Ken Griffey diff --git a/src/ext_depends/D-YAML/test/data/spec-02-01.structure b/src/ext_depends/D-YAML/test/data/spec-02-01.structure new file mode 100644 index 0000000..f532f4a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-01.structure @@ -0,0 +1 @@ +[True, True, True] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-01.tokens b/src/ext_depends/D-YAML/test/data/spec-02-01.tokens new file mode 100644 index 0000000..ce44cac --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-01.tokens @@ -0,0 +1 @@ +[[ , _ , _ , _ ]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-02.data b/src/ext_depends/D-YAML/test/data/spec-02-02.data new file mode 100644 index 0000000..7b7ec94 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-02.data @@ -0,0 +1,3 @@ +hr: 65 # Home runs +avg: 0.278 # Batting average +rbi: 147 # Runs Batted In diff --git a/src/ext_depends/D-YAML/test/data/spec-02-02.structure b/src/ext_depends/D-YAML/test/data/spec-02-02.structure new file mode 100644 index 0000000..aba1ced --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-02.structure @@ -0,0 +1 @@ +[(True, True), (True, True), (True, True)] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-02.tokens b/src/ext_depends/D-YAML/test/data/spec-02-02.tokens new file mode 100644 index 0000000..e4e381b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-02.tokens @@ -0,0 +1,5 @@ +{{ +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-03.data b/src/ext_depends/D-YAML/test/data/spec-02-03.data new file mode 100644 index 0000000..656d628 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-03.data @@ -0,0 +1,8 @@ +american: + - Boston Red Sox + - Detroit Tigers + - New York Yankees +national: + - New York Mets + - Chicago Cubs + - Atlanta Braves diff --git a/src/ext_depends/D-YAML/test/data/spec-02-03.structure b/src/ext_depends/D-YAML/test/data/spec-02-03.structure new file mode 100644 index 0000000..25de5d2 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-03.structure @@ -0,0 +1 @@ +[(True, [True, True, True]), (True, [True, True, True])] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-03.tokens b/src/ext_depends/D-YAML/test/data/spec-02-03.tokens new file mode 100644 index 0000000..89815f2 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-03.tokens @@ -0,0 +1,4 @@ +{{ +? _ : [[ , _ , _ , _ ]} +? _ : [[ , _ , _ , _ ]} +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-04.data b/src/ext_depends/D-YAML/test/data/spec-02-04.data new file mode 100644 index 0000000..430f6b3 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-04.data @@ -0,0 +1,8 @@ +- + name: Mark McGwire + hr: 65 + avg: 0.278 +- + name: Sammy Sosa + hr: 63 + avg: 0.288 diff --git a/src/ext_depends/D-YAML/test/data/spec-02-04.structure b/src/ext_depends/D-YAML/test/data/spec-02-04.structure new file mode 100644 index 0000000..e7b526c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-04.structure @@ -0,0 +1,4 @@ +[ + [(True, True), (True, True), (True, True)], + [(True, True), (True, True), (True, True)], +] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-04.tokens b/src/ext_depends/D-YAML/test/data/spec-02-04.tokens new file mode 100644 index 0000000..9cb9815 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-04.tokens @@ -0,0 +1,4 @@ +[[ +, {{ ? _ : _ ? _ : _ ? _ : _ ]} +, {{ ? _ : _ ? _ : _ ? _ : _ ]} +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-05.data b/src/ext_depends/D-YAML/test/data/spec-02-05.data new file mode 100644 index 0000000..cdd7770 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-05.data @@ -0,0 +1,3 @@ +- [name , hr, avg ] +- [Mark McGwire, 65, 0.278] +- [Sammy Sosa , 63, 0.288] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-05.structure b/src/ext_depends/D-YAML/test/data/spec-02-05.structure new file mode 100644 index 0000000..e06b75a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-05.structure @@ -0,0 +1,5 @@ +[ + [True, True, True], + [True, True, True], + [True, True, True], +] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-05.tokens b/src/ext_depends/D-YAML/test/data/spec-02-05.tokens new file mode 100644 index 0000000..3f6f1ab --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-05.tokens @@ -0,0 +1,5 @@ +[[ +, [ _ , _ , _ ] +, [ _ , _ , _ ] +, [ _ , _ , _ ] +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-06.data b/src/ext_depends/D-YAML/test/data/spec-02-06.data new file mode 100644 index 0000000..7a957b2 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-06.data @@ -0,0 +1,5 @@ +Mark McGwire: {hr: 65, avg: 0.278} +Sammy Sosa: { + hr: 63, + avg: 0.288 + } diff --git a/src/ext_depends/D-YAML/test/data/spec-02-06.structure b/src/ext_depends/D-YAML/test/data/spec-02-06.structure new file mode 100644 index 0000000..3ef0f4b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-06.structure @@ -0,0 +1,4 @@ +[ + (True, [(True, True), (True, True)]), + (True, [(True, True), (True, True)]), +] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-06.tokens b/src/ext_depends/D-YAML/test/data/spec-02-06.tokens new file mode 100644 index 0000000..a1a5eef --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-06.tokens @@ -0,0 +1,4 @@ +{{ +? _ : { ? _ : _ , ? _ : _ } +? _ : { ? _ : _ , ? _ : _ } +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-07.data b/src/ext_depends/D-YAML/test/data/spec-02-07.data new file mode 100644 index 0000000..bc711d5 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-07.data @@ -0,0 +1,10 @@ +# Ranking of 1998 home runs +--- +- Mark McGwire +- Sammy Sosa +- Ken Griffey + +# Team ranking +--- +- Chicago Cubs +- St Louis Cardinals diff --git a/src/ext_depends/D-YAML/test/data/spec-02-07.structure b/src/ext_depends/D-YAML/test/data/spec-02-07.structure new file mode 100644 index 0000000..c5d72a3 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-07.structure @@ -0,0 +1,4 @@ +[ +[True, True, True], +[True, True], +] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-07.tokens b/src/ext_depends/D-YAML/test/data/spec-02-07.tokens new file mode 100644 index 0000000..ed48883 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-07.tokens @@ -0,0 +1,12 @@ +--- +[[ +, _ +, _ +, _ +]} + +--- +[[ +, _ +, _ +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-08.data b/src/ext_depends/D-YAML/test/data/spec-02-08.data new file mode 100644 index 0000000..05e102d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-08.data @@ -0,0 +1,10 @@ +--- +time: 20:03:20 +player: Sammy Sosa +action: strike (miss) +... +--- +time: 20:03:47 +player: Sammy Sosa +action: grand slam +... diff --git a/src/ext_depends/D-YAML/test/data/spec-02-08.structure b/src/ext_depends/D-YAML/test/data/spec-02-08.structure new file mode 100644 index 0000000..24cff73 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-08.structure @@ -0,0 +1,4 @@ +[ +[(True, True), (True, True), (True, True)], +[(True, True), (True, True), (True, True)], +] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-08.tokens b/src/ext_depends/D-YAML/test/data/spec-02-08.tokens new file mode 100644 index 0000000..7d2c03d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-08.tokens @@ -0,0 +1,15 @@ +--- +{{ +? _ : _ +? _ : _ +? _ : _ +]} +... + +--- +{{ +? _ : _ +? _ : _ +? _ : _ +]} +... diff --git a/src/ext_depends/D-YAML/test/data/spec-02-09.data b/src/ext_depends/D-YAML/test/data/spec-02-09.data new file mode 100644 index 0000000..e264180 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-09.data @@ -0,0 +1,8 @@ +--- +hr: # 1998 hr ranking + - Mark McGwire + - Sammy Sosa +rbi: + # 1998 rbi ranking + - Sammy Sosa + - Ken Griffey diff --git a/src/ext_depends/D-YAML/test/data/spec-02-09.structure b/src/ext_depends/D-YAML/test/data/spec-02-09.structure new file mode 100644 index 0000000..b4c9914 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-09.structure @@ -0,0 +1 @@ +[(True, [True, True]), (True, [True, True])] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-09.tokens b/src/ext_depends/D-YAML/test/data/spec-02-09.tokens new file mode 100644 index 0000000..b2ec10e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-09.tokens @@ -0,0 +1,5 @@ +--- +{{ +? _ : [[ , _ , _ ]} +? _ : [[ , _ , _ ]} +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-10.data b/src/ext_depends/D-YAML/test/data/spec-02-10.data new file mode 100644 index 0000000..61808f6 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-10.data @@ -0,0 +1,8 @@ +--- +hr: + - Mark McGwire + # Following node labeled SS + - &SS Sammy Sosa +rbi: + - *SS # Subsequent occurrence + - Ken Griffey diff --git a/src/ext_depends/D-YAML/test/data/spec-02-10.structure b/src/ext_depends/D-YAML/test/data/spec-02-10.structure new file mode 100644 index 0000000..ff8f4c3 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-10.structure @@ -0,0 +1 @@ +[(True, [True, True]), (True, ['*', True])] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-10.tokens b/src/ext_depends/D-YAML/test/data/spec-02-10.tokens new file mode 100644 index 0000000..26caa2b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-10.tokens @@ -0,0 +1,5 @@ +--- +{{ +? _ : [[ , _ , & _ ]} +? _ : [[ , * , _ ]} +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-11.data b/src/ext_depends/D-YAML/test/data/spec-02-11.data new file mode 100644 index 0000000..9123ce2 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-11.data @@ -0,0 +1,9 @@ +? - Detroit Tigers + - Chicago cubs +: + - 2001-07-23 + +? [ New York Yankees, + Atlanta Braves ] +: [ 2001-07-02, 2001-08-12, + 2001-08-14 ] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-11.structure b/src/ext_depends/D-YAML/test/data/spec-02-11.structure new file mode 100644 index 0000000..3d8f1ff --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-11.structure @@ -0,0 +1,4 @@ +[ +([True, True], [True]), +([True, True], [True, True, True]), +] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-11.tokens b/src/ext_depends/D-YAML/test/data/spec-02-11.tokens new file mode 100644 index 0000000..fe24203 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-11.tokens @@ -0,0 +1,6 @@ +{{ +? [[ , _ , _ ]} +: [[ , _ ]} +? [ _ , _ ] +: [ _ , _ , _ ] +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-12.data b/src/ext_depends/D-YAML/test/data/spec-02-12.data new file mode 100644 index 0000000..1fc33f9 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-12.data @@ -0,0 +1,8 @@ +--- +# products purchased +- item : Super Hoop + quantity: 1 +- item : Basketball + quantity: 4 +- item : Big Shoes + quantity: 1 diff --git a/src/ext_depends/D-YAML/test/data/spec-02-12.structure b/src/ext_depends/D-YAML/test/data/spec-02-12.structure new file mode 100644 index 0000000..e9c5359 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-12.structure @@ -0,0 +1,5 @@ +[ +[(True, True), (True, True)], +[(True, True), (True, True)], +[(True, True), (True, True)], +] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-12.tokens b/src/ext_depends/D-YAML/test/data/spec-02-12.tokens new file mode 100644 index 0000000..ea21e50 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-12.tokens @@ -0,0 +1,6 @@ +--- +[[ +, {{ ? _ : _ ? _ : _ ]} +, {{ ? _ : _ ? _ : _ ]} +, {{ ? _ : _ ? _ : _ ]} +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-13.data b/src/ext_depends/D-YAML/test/data/spec-02-13.data new file mode 100644 index 0000000..13fb656 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-13.data @@ -0,0 +1,4 @@ +# ASCII Art +--- | + \//||\/|| + // || ||__ diff --git a/src/ext_depends/D-YAML/test/data/spec-02-13.structure b/src/ext_depends/D-YAML/test/data/spec-02-13.structure new file mode 100644 index 0000000..0ca9514 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-13.structure @@ -0,0 +1 @@ +True diff --git a/src/ext_depends/D-YAML/test/data/spec-02-13.tokens b/src/ext_depends/D-YAML/test/data/spec-02-13.tokens new file mode 100644 index 0000000..7456c05 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-13.tokens @@ -0,0 +1 @@ +--- _ diff --git a/src/ext_depends/D-YAML/test/data/spec-02-14.data b/src/ext_depends/D-YAML/test/data/spec-02-14.data new file mode 100644 index 0000000..59943de --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-14.data @@ -0,0 +1,4 @@ +--- + Mark McGwire's + year was crippled + by a knee injury. diff --git a/src/ext_depends/D-YAML/test/data/spec-02-14.structure b/src/ext_depends/D-YAML/test/data/spec-02-14.structure new file mode 100644 index 0000000..0ca9514 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-14.structure @@ -0,0 +1 @@ +True diff --git a/src/ext_depends/D-YAML/test/data/spec-02-14.tokens b/src/ext_depends/D-YAML/test/data/spec-02-14.tokens new file mode 100644 index 0000000..7456c05 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-14.tokens @@ -0,0 +1 @@ +--- _ diff --git a/src/ext_depends/D-YAML/test/data/spec-02-15.data b/src/ext_depends/D-YAML/test/data/spec-02-15.data new file mode 100644 index 0000000..80b89a6 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-15.data @@ -0,0 +1,8 @@ +> + Sammy Sosa completed another + fine season with great stats. + + 63 Home Runs + 0.288 Batting Average + + What a year! diff --git a/src/ext_depends/D-YAML/test/data/spec-02-15.structure b/src/ext_depends/D-YAML/test/data/spec-02-15.structure new file mode 100644 index 0000000..0ca9514 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-15.structure @@ -0,0 +1 @@ +True diff --git a/src/ext_depends/D-YAML/test/data/spec-02-15.tokens b/src/ext_depends/D-YAML/test/data/spec-02-15.tokens new file mode 100644 index 0000000..31354ec --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-15.tokens @@ -0,0 +1 @@ +_ diff --git a/src/ext_depends/D-YAML/test/data/spec-02-16.data b/src/ext_depends/D-YAML/test/data/spec-02-16.data new file mode 100644 index 0000000..9f66d88 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-16.data @@ -0,0 +1,7 @@ +name: Mark McGwire +accomplishment: > + Mark set a major league + home run record in 1998. +stats: | + 65 Home Runs + 0.278 Batting Average diff --git a/src/ext_depends/D-YAML/test/data/spec-02-16.structure b/src/ext_depends/D-YAML/test/data/spec-02-16.structure new file mode 100644 index 0000000..aba1ced --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-16.structure @@ -0,0 +1 @@ +[(True, True), (True, True), (True, True)] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-16.tokens b/src/ext_depends/D-YAML/test/data/spec-02-16.tokens new file mode 100644 index 0000000..e4e381b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-16.tokens @@ -0,0 +1,5 @@ +{{ +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-17.data b/src/ext_depends/D-YAML/test/data/spec-02-17.data new file mode 100644 index 0000000..b2870c5 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-17.data @@ -0,0 +1,7 @@ +unicode: "Sosa did fine.\u263A" +control: "\b1998\t1999\t2000\n" +hexesc: "\x13\x10 is \r\n" + +single: '"Howdy!" he cried.' +quoted: ' # not a ''comment''.' +tie-fighter: '|\-*-/|' diff --git a/src/ext_depends/D-YAML/test/data/spec-02-17.structure b/src/ext_depends/D-YAML/test/data/spec-02-17.structure new file mode 100644 index 0000000..933646d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-17.structure @@ -0,0 +1 @@ +[(True, True), (True, True), (True, True), (True, True), (True, True), (True, True)] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-17.tokens b/src/ext_depends/D-YAML/test/data/spec-02-17.tokens new file mode 100644 index 0000000..db65540 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-17.tokens @@ -0,0 +1,8 @@ +{{ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-18.data b/src/ext_depends/D-YAML/test/data/spec-02-18.data new file mode 100644 index 0000000..e0a8bfa --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-18.data @@ -0,0 +1,6 @@ +plain: + This unquoted scalar + spans many lines. + +quoted: "So does this + quoted scalar.\n" diff --git a/src/ext_depends/D-YAML/test/data/spec-02-18.structure b/src/ext_depends/D-YAML/test/data/spec-02-18.structure new file mode 100644 index 0000000..0ca4991 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-18.structure @@ -0,0 +1 @@ +[(True, True), (True, True)] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-18.tokens b/src/ext_depends/D-YAML/test/data/spec-02-18.tokens new file mode 100644 index 0000000..83b31dc --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-18.tokens @@ -0,0 +1,4 @@ +{{ +? _ : _ +? _ : _ +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-19.data b/src/ext_depends/D-YAML/test/data/spec-02-19.data new file mode 100644 index 0000000..bf69de6 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-19.data @@ -0,0 +1,5 @@ +canonical: 12345 +decimal: +12,345 +sexagesimal: 3:25:45 +octal: 014 +hexadecimal: 0xC diff --git a/src/ext_depends/D-YAML/test/data/spec-02-19.structure b/src/ext_depends/D-YAML/test/data/spec-02-19.structure new file mode 100644 index 0000000..48ca99d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-19.structure @@ -0,0 +1 @@ +[(True, True), (True, True), (True, True), (True, True), (True, True)] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-19.tokens b/src/ext_depends/D-YAML/test/data/spec-02-19.tokens new file mode 100644 index 0000000..5bda68f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-19.tokens @@ -0,0 +1,7 @@ +{{ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-20.data b/src/ext_depends/D-YAML/test/data/spec-02-20.data new file mode 100644 index 0000000..1d4897f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-20.data @@ -0,0 +1,6 @@ +canonical: 1.23015e+3 +exponential: 12.3015e+02 +sexagesimal: 20:30.15 +fixed: 1,230.15 +negative infinity: -.inf +not a number: .NaN diff --git a/src/ext_depends/D-YAML/test/data/spec-02-20.structure b/src/ext_depends/D-YAML/test/data/spec-02-20.structure new file mode 100644 index 0000000..933646d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-20.structure @@ -0,0 +1 @@ +[(True, True), (True, True), (True, True), (True, True), (True, True), (True, True)] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-20.tokens b/src/ext_depends/D-YAML/test/data/spec-02-20.tokens new file mode 100644 index 0000000..db65540 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-20.tokens @@ -0,0 +1,8 @@ +{{ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-21.data b/src/ext_depends/D-YAML/test/data/spec-02-21.data new file mode 100644 index 0000000..dec6a56 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-21.data @@ -0,0 +1,4 @@ +null: ~ +true: y +false: n +string: '12345' diff --git a/src/ext_depends/D-YAML/test/data/spec-02-21.structure b/src/ext_depends/D-YAML/test/data/spec-02-21.structure new file mode 100644 index 0000000..021635f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-21.structure @@ -0,0 +1 @@ +[(True, True), (True, True), (True, True), (True, True)] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-21.tokens b/src/ext_depends/D-YAML/test/data/spec-02-21.tokens new file mode 100644 index 0000000..aeccbaf --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-21.tokens @@ -0,0 +1,6 @@ +{{ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-22.data b/src/ext_depends/D-YAML/test/data/spec-02-22.data new file mode 100644 index 0000000..aaac185 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-22.data @@ -0,0 +1,4 @@ +canonical: 2001-12-15T02:59:43.1Z +iso8601: 2001-12-14t21:59:43.10-05:00 +spaced: 2001-12-14 21:59:43.10 -5 +date: 2002-12-14 diff --git a/src/ext_depends/D-YAML/test/data/spec-02-22.structure b/src/ext_depends/D-YAML/test/data/spec-02-22.structure new file mode 100644 index 0000000..021635f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-22.structure @@ -0,0 +1 @@ +[(True, True), (True, True), (True, True), (True, True)] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-22.tokens b/src/ext_depends/D-YAML/test/data/spec-02-22.tokens new file mode 100644 index 0000000..aeccbaf --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-22.tokens @@ -0,0 +1,6 @@ +{{ +? _ : _ +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-23.data b/src/ext_depends/D-YAML/test/data/spec-02-23.data new file mode 100644 index 0000000..5dbd992 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-23.data @@ -0,0 +1,13 @@ +--- +not-date: !!str 2002-04-28 + +picture: !!binary | + R0lGODlhDAAMAIQAAP//9/X + 17unp5WZmZgAAAOfn515eXv + Pz7Y6OjuDg4J+fn5OTk6enp + 56enmleECcgggoBADs= + +application specific tag: !something | + The semantics of the tag + above may be different for + different documents. diff --git a/src/ext_depends/D-YAML/test/data/spec-02-23.structure b/src/ext_depends/D-YAML/test/data/spec-02-23.structure new file mode 100644 index 0000000..aba1ced --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-23.structure @@ -0,0 +1 @@ +[(True, True), (True, True), (True, True)] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-23.tokens b/src/ext_depends/D-YAML/test/data/spec-02-23.tokens new file mode 100644 index 0000000..9ac54aa --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-23.tokens @@ -0,0 +1,6 @@ +--- +{{ +? _ : ! _ +? _ : ! _ +? _ : ! _ +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-24.data b/src/ext_depends/D-YAML/test/data/spec-02-24.data new file mode 100644 index 0000000..1180757 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-24.data @@ -0,0 +1,14 @@ +%TAG ! tag:clarkevans.com,2002: +--- !shape + # Use the ! handle for presenting + # tag:clarkevans.com,2002:circle +- !circle + center: &ORIGIN {x: 73, y: 129} + radius: 7 +- !line + start: *ORIGIN + finish: { x: 89, y: 102 } +- !label + start: *ORIGIN + color: 0xFFEEBB + text: Pretty vector drawing. diff --git a/src/ext_depends/D-YAML/test/data/spec-02-24.structure b/src/ext_depends/D-YAML/test/data/spec-02-24.structure new file mode 100644 index 0000000..a800729 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-24.structure @@ -0,0 +1,5 @@ +[ +[(True, [(True, True), (True, True)]), (True, True)], +[(True, '*'), (True, [(True, True), (True, True)])], +[(True, '*'), (True, True), (True, True)], +] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-24.tokens b/src/ext_depends/D-YAML/test/data/spec-02-24.tokens new file mode 100644 index 0000000..039c385 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-24.tokens @@ -0,0 +1,20 @@ +% +--- ! +[[ +, ! + {{ + ? _ : & { ? _ : _ , ? _ : _ } + ? _ : _ + ]} +, ! + {{ + ? _ : * + ? _ : { ? _ : _ , ? _ : _ } + ]} +, ! + {{ + ? _ : * + ? _ : _ + ? _ : _ + ]} +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-25.data b/src/ext_depends/D-YAML/test/data/spec-02-25.data new file mode 100644 index 0000000..769ac31 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-25.data @@ -0,0 +1,7 @@ +# sets are represented as a +# mapping where each key is +# associated with the empty string +--- !!set +? Mark McGwire +? Sammy Sosa +? Ken Griff diff --git a/src/ext_depends/D-YAML/test/data/spec-02-25.structure b/src/ext_depends/D-YAML/test/data/spec-02-25.structure new file mode 100644 index 0000000..0b40e61 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-25.structure @@ -0,0 +1 @@ +[(True, None), (True, None), (True, None)] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-25.tokens b/src/ext_depends/D-YAML/test/data/spec-02-25.tokens new file mode 100644 index 0000000..b700236 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-25.tokens @@ -0,0 +1,6 @@ +--- ! +{{ +? _ +? _ +? _ +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-26.data b/src/ext_depends/D-YAML/test/data/spec-02-26.data new file mode 100644 index 0000000..3143763 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-26.data @@ -0,0 +1,7 @@ +# ordered maps are represented as +# a sequence of mappings, with +# each mapping having one key +--- !!omap +- Mark McGwire: 65 +- Sammy Sosa: 63 +- Ken Griffy: 58 diff --git a/src/ext_depends/D-YAML/test/data/spec-02-26.structure b/src/ext_depends/D-YAML/test/data/spec-02-26.structure new file mode 100644 index 0000000..cf429b9 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-26.structure @@ -0,0 +1,5 @@ +[ +[(True, True)], +[(True, True)], +[(True, True)], +] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-26.tokens b/src/ext_depends/D-YAML/test/data/spec-02-26.tokens new file mode 100644 index 0000000..7bee492 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-26.tokens @@ -0,0 +1,6 @@ +--- ! +[[ +, {{ ? _ : _ ]} +, {{ ? _ : _ ]} +, {{ ? _ : _ ]} +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-27.data b/src/ext_depends/D-YAML/test/data/spec-02-27.data new file mode 100644 index 0000000..4625739 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-27.data @@ -0,0 +1,29 @@ +--- !<tag:clarkevans.com,2002:invoice> +invoice: 34843 +date : 2001-01-23 +bill-to: &id001 + given : Chris + family : Dumars + address: + lines: | + 458 Walkman Dr. + Suite #292 + city : Royal Oak + state : MI + postal : 48046 +ship-to: *id001 +product: + - sku : BL394D + quantity : 4 + description : Basketball + price : 450.00 + - sku : BL4438H + quantity : 1 + description : Super Hoop + price : 2392.00 +tax : 251.42 +total: 4443.52 +comments: + Late afternoon is best. + Backup contact is Nancy + Billsmer @ 338-4338. diff --git a/src/ext_depends/D-YAML/test/data/spec-02-27.structure b/src/ext_depends/D-YAML/test/data/spec-02-27.structure new file mode 100644 index 0000000..a2113b9 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-27.structure @@ -0,0 +1,17 @@ +[ +(True, True), +(True, True), +(True, [ + (True, True), + (True, True), + (True, [(True, True), (True, True), (True, True), (True, True)]), + ]), +(True, '*'), +(True, [ + [(True, True), (True, True), (True, True), (True, True)], + [(True, True), (True, True), (True, True), (True, True)], + ]), +(True, True), +(True, True), +(True, True), +] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-27.tokens b/src/ext_depends/D-YAML/test/data/spec-02-27.tokens new file mode 100644 index 0000000..2dc1c25 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-27.tokens @@ -0,0 +1,20 @@ +--- ! +{{ +? _ : _ +? _ : _ +? _ : & + {{ + ? _ : _ + ? _ : _ + ? _ : {{ ? _ : _ ? _ : _ ? _ : _ ? _ : _ ]} + ]} +? _ : * +? _ : + [[ + , {{ ? _ : _ ? _ : _ ? _ : _ ? _ : _ ]} + , {{ ? _ : _ ? _ : _ ? _ : _ ? _ : _ ]} + ]} +? _ : _ +? _ : _ +? _ : _ +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-02-28.data b/src/ext_depends/D-YAML/test/data/spec-02-28.data new file mode 100644 index 0000000..a5c8dc8 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-28.data @@ -0,0 +1,26 @@ +--- +Time: 2001-11-23 15:01:42 -5 +User: ed +Warning: + This is an error message + for the log file +--- +Time: 2001-11-23 15:02:31 -5 +User: ed +Warning: + A slightly different error + message. +--- +Date: 2001-11-23 15:03:17 -5 +User: ed +Fatal: + Unknown variable "bar" +Stack: + - file: TopClass.py + line: 23 + code: | + x = MoreObject("345\n") + - file: MoreClass.py + line: 58 + code: |- + foo = bar diff --git a/src/ext_depends/D-YAML/test/data/spec-02-28.structure b/src/ext_depends/D-YAML/test/data/spec-02-28.structure new file mode 100644 index 0000000..8ec0b56 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-28.structure @@ -0,0 +1,10 @@ +[ +[(True, True), (True, True), (True, True)], +[(True, True), (True, True), (True, True)], +[(True, True), (True, True), (True, True), +(True, [ + [(True, True), (True, True), (True, True)], + [(True, True), (True, True), (True, True)], + ]), +] +] diff --git a/src/ext_depends/D-YAML/test/data/spec-02-28.tokens b/src/ext_depends/D-YAML/test/data/spec-02-28.tokens new file mode 100644 index 0000000..8d5e1bc --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-02-28.tokens @@ -0,0 +1,23 @@ +--- +{{ +? _ : _ +? _ : _ +? _ : _ +]} +--- +{{ +? _ : _ +? _ : _ +? _ : _ +]} +--- +{{ +? _ : _ +? _ : _ +? _ : _ +? _ : + [[ + , {{ ? _ : _ ? _ : _ ? _ : _ ]} + , {{ ? _ : _ ? _ : _ ? _ : _ ]} + ]} +]} diff --git a/src/ext_depends/D-YAML/test/data/spec-05-01-utf16be.data b/src/ext_depends/D-YAML/test/data/spec-05-01-utf16be.data Binary files differnew file mode 100644 index 0000000..3525062 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-01-utf16be.data diff --git a/src/ext_depends/D-YAML/test/data/spec-05-01-utf16be.empty b/src/ext_depends/D-YAML/test/data/spec-05-01-utf16be.empty new file mode 100644 index 0000000..bfffa8b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-01-utf16be.empty @@ -0,0 +1,2 @@ +# This stream contains no +# documents, only comments. diff --git a/src/ext_depends/D-YAML/test/data/spec-05-01-utf16le.data b/src/ext_depends/D-YAML/test/data/spec-05-01-utf16le.data Binary files differnew file mode 100644 index 0000000..0823f74 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-01-utf16le.data diff --git a/src/ext_depends/D-YAML/test/data/spec-05-01-utf16le.empty b/src/ext_depends/D-YAML/test/data/spec-05-01-utf16le.empty new file mode 100644 index 0000000..bfffa8b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-01-utf16le.empty @@ -0,0 +1,2 @@ +# This stream contains no +# documents, only comments. diff --git a/src/ext_depends/D-YAML/test/data/spec-05-01-utf8.data b/src/ext_depends/D-YAML/test/data/spec-05-01-utf8.data new file mode 100644 index 0000000..780d25b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-01-utf8.data @@ -0,0 +1 @@ +# Comment only. diff --git a/src/ext_depends/D-YAML/test/data/spec-05-01-utf8.empty b/src/ext_depends/D-YAML/test/data/spec-05-01-utf8.empty new file mode 100644 index 0000000..bfffa8b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-01-utf8.empty @@ -0,0 +1,2 @@ +# This stream contains no +# documents, only comments. diff --git a/src/ext_depends/D-YAML/test/data/spec-05-02-utf16be.data b/src/ext_depends/D-YAML/test/data/spec-05-02-utf16be.data Binary files differnew file mode 100644 index 0000000..5ebbb04 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-02-utf16be.data diff --git a/src/ext_depends/D-YAML/test/data/spec-05-02-utf16be.error b/src/ext_depends/D-YAML/test/data/spec-05-02-utf16be.error new file mode 100644 index 0000000..1df3616 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-02-utf16be.error @@ -0,0 +1,3 @@ +ERROR: + A BOM must not appear + inside a document. diff --git a/src/ext_depends/D-YAML/test/data/spec-05-02-utf16le.data b/src/ext_depends/D-YAML/test/data/spec-05-02-utf16le.data Binary files differnew file mode 100644 index 0000000..0cd90a2 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-02-utf16le.data diff --git a/src/ext_depends/D-YAML/test/data/spec-05-02-utf16le.error b/src/ext_depends/D-YAML/test/data/spec-05-02-utf16le.error new file mode 100644 index 0000000..1df3616 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-02-utf16le.error @@ -0,0 +1,3 @@ +ERROR: + A BOM must not appear + inside a document. diff --git a/src/ext_depends/D-YAML/test/data/spec-05-02-utf8.data b/src/ext_depends/D-YAML/test/data/spec-05-02-utf8.data new file mode 100644 index 0000000..fb74866 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-02-utf8.data @@ -0,0 +1,3 @@ +# Invalid use of BOM +# inside a +# document. diff --git a/src/ext_depends/D-YAML/test/data/spec-05-02-utf8.error b/src/ext_depends/D-YAML/test/data/spec-05-02-utf8.error new file mode 100644 index 0000000..1df3616 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-02-utf8.error @@ -0,0 +1,3 @@ +ERROR: + A BOM must not appear + inside a document. diff --git a/src/ext_depends/D-YAML/test/data/spec-05-03.canonical b/src/ext_depends/D-YAML/test/data/spec-05-03.canonical new file mode 100644 index 0000000..a143a73 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-03.canonical @@ -0,0 +1,14 @@ +%YAML 1.1 +--- +!!map { + ? !!str "sequence" + : !!seq [ + !!str "one", !!str "two" + ], + ? !!str "mapping" + : !!map { + ? !!str "sky" : !!str "blue", +# ? !!str "sea" : !!str "green", + ? !!map { ? !!str "sea" : !!str "green" } : !!null "", + } +} diff --git a/src/ext_depends/D-YAML/test/data/spec-05-03.data b/src/ext_depends/D-YAML/test/data/spec-05-03.data new file mode 100644 index 0000000..4661f33 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-03.data @@ -0,0 +1,7 @@ +sequence: +- one +- two +mapping: + ? sky + : blue + ? sea : green diff --git a/src/ext_depends/D-YAML/test/data/spec-05-04.canonical b/src/ext_depends/D-YAML/test/data/spec-05-04.canonical new file mode 100644 index 0000000..00c9723 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-04.canonical @@ -0,0 +1,13 @@ +%YAML 1.1 +--- +!!map { + ? !!str "sequence" + : !!seq [ + !!str "one", !!str "two" + ], + ? !!str "mapping" + : !!map { + ? !!str "sky" : !!str "blue", + ? !!str "sea" : !!str "green", + } +} diff --git a/src/ext_depends/D-YAML/test/data/spec-05-04.data b/src/ext_depends/D-YAML/test/data/spec-05-04.data new file mode 100644 index 0000000..df33847 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-04.data @@ -0,0 +1,2 @@ +sequence: [ one, two, ] +mapping: { sky: blue, sea: green } diff --git a/src/ext_depends/D-YAML/test/data/spec-05-05.data b/src/ext_depends/D-YAML/test/data/spec-05-05.data new file mode 100644 index 0000000..62524c0 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-05.data @@ -0,0 +1 @@ +# Comment only. diff --git a/src/ext_depends/D-YAML/test/data/spec-05-05.empty b/src/ext_depends/D-YAML/test/data/spec-05-05.empty new file mode 100644 index 0000000..bfffa8b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-05.empty @@ -0,0 +1,2 @@ +# This stream contains no +# documents, only comments. diff --git a/src/ext_depends/D-YAML/test/data/spec-05-06.canonical b/src/ext_depends/D-YAML/test/data/spec-05-06.canonical new file mode 100644 index 0000000..4f30c11 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-06.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!map { + ? !!str "anchored" + : &A1 !local "value", + ? !!str "alias" + : *A1, +} diff --git a/src/ext_depends/D-YAML/test/data/spec-05-06.data b/src/ext_depends/D-YAML/test/data/spec-05-06.data new file mode 100644 index 0000000..7a1f9b3 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-06.data @@ -0,0 +1,2 @@ +anchored: !local &anchor value +alias: *anchor diff --git a/src/ext_depends/D-YAML/test/data/spec-05-06.test_loader_skip b/src/ext_depends/D-YAML/test/data/spec-05-06.test_loader_skip new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-06.test_loader_skip diff --git a/src/ext_depends/D-YAML/test/data/spec-05-07.canonical b/src/ext_depends/D-YAML/test/data/spec-05-07.canonical new file mode 100644 index 0000000..dc3732a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-07.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!map { + ? !!str "literal" + : !!str "text\n", + ? !!str "folded" + : !!str "text\n", +} diff --git a/src/ext_depends/D-YAML/test/data/spec-05-07.data b/src/ext_depends/D-YAML/test/data/spec-05-07.data new file mode 100644 index 0000000..97eb3a3 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-07.data @@ -0,0 +1,4 @@ +literal: | + text +folded: > + text diff --git a/src/ext_depends/D-YAML/test/data/spec-05-08.canonical b/src/ext_depends/D-YAML/test/data/spec-05-08.canonical new file mode 100644 index 0000000..610bd68 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-08.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!map { + ? !!str "single" + : !!str "text", + ? !!str "double" + : !!str "text", +} diff --git a/src/ext_depends/D-YAML/test/data/spec-05-08.data b/src/ext_depends/D-YAML/test/data/spec-05-08.data new file mode 100644 index 0000000..04ebf69 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-08.data @@ -0,0 +1,2 @@ +single: 'text' +double: "text" diff --git a/src/ext_depends/D-YAML/test/data/spec-05-09.canonical b/src/ext_depends/D-YAML/test/data/spec-05-09.canonical new file mode 100644 index 0000000..597e3de --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-09.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "text" diff --git a/src/ext_depends/D-YAML/test/data/spec-05-09.data b/src/ext_depends/D-YAML/test/data/spec-05-09.data new file mode 100644 index 0000000..a43431b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-09.data @@ -0,0 +1,2 @@ +%YAML 1.1 +--- text diff --git a/src/ext_depends/D-YAML/test/data/spec-05-10.data b/src/ext_depends/D-YAML/test/data/spec-05-10.data new file mode 100644 index 0000000..a4caf91 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-10.data @@ -0,0 +1,2 @@ +commercial-at: @text +grave-accent: `text diff --git a/src/ext_depends/D-YAML/test/data/spec-05-10.error b/src/ext_depends/D-YAML/test/data/spec-05-10.error new file mode 100644 index 0000000..46f776e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-10.error @@ -0,0 +1,3 @@ +ERROR: + Reserved indicators can't + start a plain scalar. diff --git a/src/ext_depends/D-YAML/test/data/spec-05-11.canonical b/src/ext_depends/D-YAML/test/data/spec-05-11.canonical new file mode 100644 index 0000000..fc25bef --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-11.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- !!str +"Generic line break (no glyph)\n\ + Generic line break (glyphed)\n\ + Line separator\u2028\ + Paragraph separator\u2029" diff --git a/src/ext_depends/D-YAML/test/data/spec-05-11.data b/src/ext_depends/D-YAML/test/data/spec-05-11.data new file mode 100644 index 0000000..b448b75 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-11.data @@ -0,0 +1,3 @@ +| + Generic line break (no glyph) + Generic line break (glyphed)
Line separator
Paragraph separator
\ No newline at end of file diff --git a/src/ext_depends/D-YAML/test/data/spec-05-12.data b/src/ext_depends/D-YAML/test/data/spec-05-12.data new file mode 100644 index 0000000..7c3ad7f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-12.data @@ -0,0 +1,9 @@ +# Tabs do's and don'ts: +# comment: +quoted: "Quoted " +block: | + void main() { + printf("Hello, world!\n"); + } +elsewhere: # separation + indentation, in plain scalar diff --git a/src/ext_depends/D-YAML/test/data/spec-05-12.error b/src/ext_depends/D-YAML/test/data/spec-05-12.error new file mode 100644 index 0000000..8aad4c8 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-12.error @@ -0,0 +1,8 @@ +ERROR: + Tabs may appear inside + comments and quoted or + block scalar content. + Tabs must not appear + elsewhere, such as + in indentation and + separation spaces. diff --git a/src/ext_depends/D-YAML/test/data/spec-05-13.canonical b/src/ext_depends/D-YAML/test/data/spec-05-13.canonical new file mode 100644 index 0000000..90c1c5c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-13.canonical @@ -0,0 +1,5 @@ +%YAML 1.1 +--- !!str +"Text containing \ + both space and \ + tab characters" diff --git a/src/ext_depends/D-YAML/test/data/spec-05-13.data b/src/ext_depends/D-YAML/test/data/spec-05-13.data new file mode 100644 index 0000000..fce7951 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-13.data @@ -0,0 +1,3 @@ + "Text containing + both space and + tab characters" diff --git a/src/ext_depends/D-YAML/test/data/spec-05-14.canonical b/src/ext_depends/D-YAML/test/data/spec-05-14.canonical new file mode 100644 index 0000000..4bff01c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-14.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +"Fun with \x5C + \x22 \x07 \x08 \x1B \x0C + \x0A \x0D \x09 \x0B \x00 + \x20 \xA0 \x85 \u2028 \u2029 + A A A" diff --git a/src/ext_depends/D-YAML/test/data/spec-05-14.data b/src/ext_depends/D-YAML/test/data/spec-05-14.data new file mode 100644 index 0000000..d6e8ce4 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-14.data @@ -0,0 +1,2 @@ +"Fun with \\ + \" \a \b \e \f \
\n \r \t \v \0 \
\ \_ \N \L \P \
\x41 \u0041 \U00000041" diff --git a/src/ext_depends/D-YAML/test/data/spec-05-15.data b/src/ext_depends/D-YAML/test/data/spec-05-15.data new file mode 100644 index 0000000..7bf12b6 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-15.data @@ -0,0 +1,3 @@ +Bad escapes: + "\c + \xq-" diff --git a/src/ext_depends/D-YAML/test/data/spec-05-15.error b/src/ext_depends/D-YAML/test/data/spec-05-15.error new file mode 100644 index 0000000..71ffbd9 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-05-15.error @@ -0,0 +1,3 @@ +ERROR: +- c is an invalid escaped character. +- q and - are invalid hex digits. diff --git a/src/ext_depends/D-YAML/test/data/spec-06-01.canonical b/src/ext_depends/D-YAML/test/data/spec-06-01.canonical new file mode 100644 index 0000000..f17ec92 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-01.canonical @@ -0,0 +1,15 @@ +%YAML 1.1 +--- +!!map { + ? !!str "Not indented" + : !!map { + ? !!str "By one space" + : !!str "By four\n spaces\n", + ? !!str "Flow style" + : !!seq [ + !!str "By two", + !!str "Also by two", + !!str "Still by two", + ] + } +} diff --git a/src/ext_depends/D-YAML/test/data/spec-06-01.data b/src/ext_depends/D-YAML/test/data/spec-06-01.data new file mode 100644 index 0000000..6134ba1 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-01.data @@ -0,0 +1,14 @@ + # Leading comment line spaces are + # neither content nor indentation. + +Not indented: + By one space: | + By four + spaces + Flow style: [ # Leading spaces + By two, # in flow style + Also by two, # are neither +# Tabs are not allowed: +# Still by two # content nor + Still by two # content nor + ] # indentation. diff --git a/src/ext_depends/D-YAML/test/data/spec-06-02.data b/src/ext_depends/D-YAML/test/data/spec-06-02.data new file mode 100644 index 0000000..ff741e5 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-02.data @@ -0,0 +1,3 @@ + # Comment + + diff --git a/src/ext_depends/D-YAML/test/data/spec-06-02.empty b/src/ext_depends/D-YAML/test/data/spec-06-02.empty new file mode 100644 index 0000000..bfffa8b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-02.empty @@ -0,0 +1,2 @@ +# This stream contains no +# documents, only comments. diff --git a/src/ext_depends/D-YAML/test/data/spec-06-03.canonical b/src/ext_depends/D-YAML/test/data/spec-06-03.canonical new file mode 100644 index 0000000..ec26902 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-03.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!map { + ? !!str "key" + : !!str "value" +} diff --git a/src/ext_depends/D-YAML/test/data/spec-06-03.data b/src/ext_depends/D-YAML/test/data/spec-06-03.data new file mode 100644 index 0000000..9db0912 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-03.data @@ -0,0 +1,2 @@ +key: # Comment + value diff --git a/src/ext_depends/D-YAML/test/data/spec-06-04.canonical b/src/ext_depends/D-YAML/test/data/spec-06-04.canonical new file mode 100644 index 0000000..ec26902 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-04.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!map { + ? !!str "key" + : !!str "value" +} diff --git a/src/ext_depends/D-YAML/test/data/spec-06-04.data b/src/ext_depends/D-YAML/test/data/spec-06-04.data new file mode 100644 index 0000000..86308dd --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-04.data @@ -0,0 +1,4 @@ +key: # Comment + # lines + value + diff --git a/src/ext_depends/D-YAML/test/data/spec-06-05.canonical b/src/ext_depends/D-YAML/test/data/spec-06-05.canonical new file mode 100644 index 0000000..8da431d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-05.canonical @@ -0,0 +1,16 @@ +%YAML 1.1 +--- +!!map { + ? !!map { + ? !!str "first" + : !!str "Sammy", + ? !!str "last" + : !!str "Sosa" + } + : !!map { + ? !!str "hr" + : !!int "65", + ? !!str "avg" + : !!float "0.278" + } +} diff --git a/src/ext_depends/D-YAML/test/data/spec-06-05.data b/src/ext_depends/D-YAML/test/data/spec-06-05.data new file mode 100644 index 0000000..37613f5 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-05.data @@ -0,0 +1,6 @@ +{ first: Sammy, last: Sosa }: +# Statistics: + hr: # Home runs + 65 + avg: # Average + 0.278 diff --git a/src/ext_depends/D-YAML/test/data/spec-06-06.canonical b/src/ext_depends/D-YAML/test/data/spec-06-06.canonical new file mode 100644 index 0000000..513d07a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-06.canonical @@ -0,0 +1,10 @@ +%YAML 1.1 +--- +!!map { + ? !!str "plain" + : !!str "text lines", + ? !!str "quoted" + : !!str "text lines", + ? !!str "block" + : !!str "text\n lines\n" +} diff --git a/src/ext_depends/D-YAML/test/data/spec-06-06.data b/src/ext_depends/D-YAML/test/data/spec-06-06.data new file mode 100644 index 0000000..2f62d08 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-06.data @@ -0,0 +1,7 @@ +plain: text + lines +quoted: "text + lines" +block: | + text + lines diff --git a/src/ext_depends/D-YAML/test/data/spec-06-07.canonical b/src/ext_depends/D-YAML/test/data/spec-06-07.canonical new file mode 100644 index 0000000..11357e4 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-07.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!seq [ + !!str "foo\nbar", + !!str "foo\n\nbar" +] diff --git a/src/ext_depends/D-YAML/test/data/spec-06-07.data b/src/ext_depends/D-YAML/test/data/spec-06-07.data new file mode 100644 index 0000000..130cfa7 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-07.data @@ -0,0 +1,8 @@ +- foo + + bar +- |- + foo + + bar + diff --git a/src/ext_depends/D-YAML/test/data/spec-06-08.canonical b/src/ext_depends/D-YAML/test/data/spec-06-08.canonical new file mode 100644 index 0000000..cc72bc8 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-08.canonical @@ -0,0 +1,5 @@ +%YAML 1.1 +--- !!str +"specific\L\ + trimmed\n\n\n\ + as space" diff --git a/src/ext_depends/D-YAML/test/data/spec-06-08.data b/src/ext_depends/D-YAML/test/data/spec-06-08.data new file mode 100644 index 0000000..f2896ed --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-06-08.data @@ -0,0 +1,2 @@ +>- + specific
trimmed
as
space diff --git a/src/ext_depends/D-YAML/test/data/spec-07-01.canonical b/src/ext_depends/D-YAML/test/data/spec-07-01.canonical new file mode 100644 index 0000000..8c8c48d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-01.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- !!str +"foo" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-01.data b/src/ext_depends/D-YAML/test/data/spec-07-01.data new file mode 100644 index 0000000..2113eb6 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-01.data @@ -0,0 +1,3 @@ +%FOO bar baz # Should be ignored + # with a warning. +--- "foo" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-01.skip-ext b/src/ext_depends/D-YAML/test/data/spec-07-01.skip-ext new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-01.skip-ext diff --git a/src/ext_depends/D-YAML/test/data/spec-07-02.canonical b/src/ext_depends/D-YAML/test/data/spec-07-02.canonical new file mode 100644 index 0000000..cb7dd1c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-02.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "foo" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-02.data b/src/ext_depends/D-YAML/test/data/spec-07-02.data new file mode 100644 index 0000000..c8b7322 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-02.data @@ -0,0 +1,4 @@ +%YAML 1.2 # Attempt parsing + # with a warning +--- +"foo" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-02.skip-ext b/src/ext_depends/D-YAML/test/data/spec-07-02.skip-ext new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-02.skip-ext diff --git a/src/ext_depends/D-YAML/test/data/spec-07-03.data b/src/ext_depends/D-YAML/test/data/spec-07-03.data new file mode 100644 index 0000000..4bfa07a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-03.data @@ -0,0 +1,3 @@ +%YAML 1.1 +%YAML 1.1 +foo diff --git a/src/ext_depends/D-YAML/test/data/spec-07-03.error b/src/ext_depends/D-YAML/test/data/spec-07-03.error new file mode 100644 index 0000000..b0ac446 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-03.error @@ -0,0 +1,3 @@ +ERROR: +The YAML directive must only be +given at most once per document. diff --git a/src/ext_depends/D-YAML/test/data/spec-07-04.canonical b/src/ext_depends/D-YAML/test/data/spec-07-04.canonical new file mode 100644 index 0000000..cb7dd1c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-04.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "foo" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-04.data b/src/ext_depends/D-YAML/test/data/spec-07-04.data new file mode 100644 index 0000000..50f5ab9 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-04.data @@ -0,0 +1,3 @@ +%TAG !yaml! tag:yaml.org,2002: +--- +!yaml!str "foo" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-05.data b/src/ext_depends/D-YAML/test/data/spec-07-05.data new file mode 100644 index 0000000..7276eae --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-05.data @@ -0,0 +1,3 @@ +%TAG ! !foo +%TAG ! !foo +bar diff --git a/src/ext_depends/D-YAML/test/data/spec-07-05.error b/src/ext_depends/D-YAML/test/data/spec-07-05.error new file mode 100644 index 0000000..5601b19 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-05.error @@ -0,0 +1,4 @@ +ERROR: +The TAG directive must only +be given at most once per +handle in the same document. diff --git a/src/ext_depends/D-YAML/test/data/spec-07-06.canonical b/src/ext_depends/D-YAML/test/data/spec-07-06.canonical new file mode 100644 index 0000000..bddf616 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-06.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!seq [ + !<!foobar> "baz", + !<tag:yaml.org,2002:str> "string" +] diff --git a/src/ext_depends/D-YAML/test/data/spec-07-06.data b/src/ext_depends/D-YAML/test/data/spec-07-06.data new file mode 100644 index 0000000..d9854cb --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-06.data @@ -0,0 +1,5 @@ +%TAG ! !foo +%TAG !yaml! tag:yaml.org,2002: +--- +- !bar "baz" +- !yaml!str "string" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-06.test_loader_skip b/src/ext_depends/D-YAML/test/data/spec-07-06.test_loader_skip new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-06.test_loader_skip diff --git a/src/ext_depends/D-YAML/test/data/spec-07-07a.canonical b/src/ext_depends/D-YAML/test/data/spec-07-07a.canonical new file mode 100644 index 0000000..fa086df --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-07a.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!<!foo> "bar" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-07a.data b/src/ext_depends/D-YAML/test/data/spec-07-07a.data new file mode 100644 index 0000000..9d42ec3 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-07a.data @@ -0,0 +1,2 @@ +# Private application: +!foo "bar" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-07a.test_loader_skip b/src/ext_depends/D-YAML/test/data/spec-07-07a.test_loader_skip new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-07a.test_loader_skip diff --git a/src/ext_depends/D-YAML/test/data/spec-07-07b.canonical b/src/ext_depends/D-YAML/test/data/spec-07-07b.canonical new file mode 100644 index 0000000..fe917d8 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-07b.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!<tag:ben-kiki.org,2000:app/foo> "bar" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-07b.data b/src/ext_depends/D-YAML/test/data/spec-07-07b.data new file mode 100644 index 0000000..2d36d0e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-07b.data @@ -0,0 +1,4 @@ +# Migrated to global: +%TAG ! tag:ben-kiki.org,2000:app/ +--- +!foo "bar" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-07b.test_loader_skip b/src/ext_depends/D-YAML/test/data/spec-07-07b.test_loader_skip new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-07b.test_loader_skip diff --git a/src/ext_depends/D-YAML/test/data/spec-07-08.canonical b/src/ext_depends/D-YAML/test/data/spec-07-08.canonical new file mode 100644 index 0000000..703aa7b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-08.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!seq [ + !<!foo> "bar", + !<tag:yaml.org,2002:str> "string", + !<tag:ben-kiki.org,2000:type> "baz" +] diff --git a/src/ext_depends/D-YAML/test/data/spec-07-08.data b/src/ext_depends/D-YAML/test/data/spec-07-08.data new file mode 100644 index 0000000..e2c6d9e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-08.data @@ -0,0 +1,9 @@ +# Explicitly specify default settings: +%TAG ! ! +%TAG !! tag:yaml.org,2002: +# Named handles have no default: +%TAG !o! tag:ben-kiki.org,2000: +--- +- !foo "bar" +- !!str "string" +- !o!type "baz" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-08.test_loader_skip b/src/ext_depends/D-YAML/test/data/spec-07-08.test_loader_skip new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-08.test_loader_skip diff --git a/src/ext_depends/D-YAML/test/data/spec-07-09.canonical b/src/ext_depends/D-YAML/test/data/spec-07-09.canonical new file mode 100644 index 0000000..32d9e94 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-09.canonical @@ -0,0 +1,9 @@ +%YAML 1.1 +--- +!!str "foo" +%YAML 1.1 +--- +!!str "bar" +%YAML 1.1 +--- +!!str "baz" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-09.data b/src/ext_depends/D-YAML/test/data/spec-07-09.data new file mode 100644 index 0000000..1209d47 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-09.data @@ -0,0 +1,11 @@ +--- +foo +... +# Repeated end marker. +... +--- +bar +# No end marker. +--- +baz +... diff --git a/src/ext_depends/D-YAML/test/data/spec-07-10.canonical b/src/ext_depends/D-YAML/test/data/spec-07-10.canonical new file mode 100644 index 0000000..1db650a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-10.canonical @@ -0,0 +1,15 @@ +%YAML 1.1 +--- +!!str "Root flow scalar" +%YAML 1.1 +--- +!!str "Root block scalar\n" +%YAML 1.1 +--- +!!map { + ? !!str "foo" + : !!str "bar" +} +--- +#!!str "" +!!null "" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-10.data b/src/ext_depends/D-YAML/test/data/spec-07-10.data new file mode 100644 index 0000000..6939b39 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-10.data @@ -0,0 +1,11 @@ +"Root flow + scalar" +--- !!str > + Root block + scalar +--- +# Root collection: +foo : bar +... # Is optional. +--- +# Explicit document may be empty. diff --git a/src/ext_depends/D-YAML/test/data/spec-07-11.data b/src/ext_depends/D-YAML/test/data/spec-07-11.data new file mode 100644 index 0000000..d11302d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-11.data @@ -0,0 +1,2 @@ +# A stream may contain +# no documents. diff --git a/src/ext_depends/D-YAML/test/data/spec-07-11.empty b/src/ext_depends/D-YAML/test/data/spec-07-11.empty new file mode 100644 index 0000000..bfffa8b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-11.empty @@ -0,0 +1,2 @@ +# This stream contains no +# documents, only comments. diff --git a/src/ext_depends/D-YAML/test/data/spec-07-12a.canonical b/src/ext_depends/D-YAML/test/data/spec-07-12a.canonical new file mode 100644 index 0000000..efc116f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-12a.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!map { + ? !!str "foo" + : !!str "bar" +} diff --git a/src/ext_depends/D-YAML/test/data/spec-07-12a.data b/src/ext_depends/D-YAML/test/data/spec-07-12a.data new file mode 100644 index 0000000..3807d57 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-12a.data @@ -0,0 +1,3 @@ +# Implicit document. Root +# collection (mapping) node. +foo : bar diff --git a/src/ext_depends/D-YAML/test/data/spec-07-12b.canonical b/src/ext_depends/D-YAML/test/data/spec-07-12b.canonical new file mode 100644 index 0000000..04bcffc --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-12b.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "Text content\n" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-12b.data b/src/ext_depends/D-YAML/test/data/spec-07-12b.data new file mode 100644 index 0000000..43250db --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-12b.data @@ -0,0 +1,4 @@ +# Explicit document. Root +# scalar (literal) node. +--- | + Text content diff --git a/src/ext_depends/D-YAML/test/data/spec-07-13.canonical b/src/ext_depends/D-YAML/test/data/spec-07-13.canonical new file mode 100644 index 0000000..5af71e9 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-13.canonical @@ -0,0 +1,9 @@ +%YAML 1.1 +--- +!!str "First document" +--- +!<!foo> "No directives" +--- +!<!foobar> "With directives" +--- +!<!baz> "Reset settings" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-13.data b/src/ext_depends/D-YAML/test/data/spec-07-13.data new file mode 100644 index 0000000..ba7ec63 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-13.data @@ -0,0 +1,9 @@ +! "First document" +--- +!foo "No directives" +%TAG ! !foo +--- +!bar "With directives" +%YAML 1.1 +--- +!baz "Reset settings" diff --git a/src/ext_depends/D-YAML/test/data/spec-07-13.test_loader_skip b/src/ext_depends/D-YAML/test/data/spec-07-13.test_loader_skip new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-07-13.test_loader_skip diff --git a/src/ext_depends/D-YAML/test/data/spec-08-01.canonical b/src/ext_depends/D-YAML/test/data/spec-08-01.canonical new file mode 100644 index 0000000..69e4161 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-01.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!map { + ? &A1 !!str "foo" + : !!str "bar", + ? &A2 !!str "baz" + : *A1 +} diff --git a/src/ext_depends/D-YAML/test/data/spec-08-01.data b/src/ext_depends/D-YAML/test/data/spec-08-01.data new file mode 100644 index 0000000..48986ec --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-01.data @@ -0,0 +1,2 @@ +!!str &a1 "foo" : !!str bar +&a2 baz : *a1 diff --git a/src/ext_depends/D-YAML/test/data/spec-08-02.canonical b/src/ext_depends/D-YAML/test/data/spec-08-02.canonical new file mode 100644 index 0000000..dd6f76e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-02.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!map { + ? !!str "First occurrence" + : &A !!str "Value", + ? !!str "Second occurrence" + : *A +} diff --git a/src/ext_depends/D-YAML/test/data/spec-08-02.data b/src/ext_depends/D-YAML/test/data/spec-08-02.data new file mode 100644 index 0000000..600d179 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-02.data @@ -0,0 +1,2 @@ +First occurrence: &anchor Value +Second occurrence: *anchor diff --git a/src/ext_depends/D-YAML/test/data/spec-08-03.canonical b/src/ext_depends/D-YAML/test/data/spec-08-03.canonical new file mode 100644 index 0000000..be7ea8f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-03.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!map { + ? !<tag:yaml.org,2002:str> "foo" + : !<!bar> "baz" +} diff --git a/src/ext_depends/D-YAML/test/data/spec-08-03.data b/src/ext_depends/D-YAML/test/data/spec-08-03.data new file mode 100644 index 0000000..8e51f52 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-03.data @@ -0,0 +1,2 @@ +!<tag:yaml.org,2002:str> foo : + !<!bar> baz diff --git a/src/ext_depends/D-YAML/test/data/spec-08-03.test_loader_skip b/src/ext_depends/D-YAML/test/data/spec-08-03.test_loader_skip new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-03.test_loader_skip diff --git a/src/ext_depends/D-YAML/test/data/spec-08-04.data b/src/ext_depends/D-YAML/test/data/spec-08-04.data new file mode 100644 index 0000000..f7d1b01 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-04.data @@ -0,0 +1,2 @@ +- !<!> foo +- !<$:?> bar diff --git a/src/ext_depends/D-YAML/test/data/spec-08-04.error b/src/ext_depends/D-YAML/test/data/spec-08-04.error new file mode 100644 index 0000000..6066375 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-04.error @@ -0,0 +1,6 @@ +ERROR: +- Verbatim tags aren't resolved, + so ! is invalid. +- The $:? tag is neither a global + URI tag nor a local tag starting + with “!”. diff --git a/src/ext_depends/D-YAML/test/data/spec-08-05.canonical b/src/ext_depends/D-YAML/test/data/spec-08-05.canonical new file mode 100644 index 0000000..a5c710a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-05.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!seq [ + !<!local> "foo", + !<tag:yaml.org,2002:str> "bar", + !<tag:ben-kiki.org,2000:type> "baz", +] diff --git a/src/ext_depends/D-YAML/test/data/spec-08-05.data b/src/ext_depends/D-YAML/test/data/spec-08-05.data new file mode 100644 index 0000000..93576ed --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-05.data @@ -0,0 +1,5 @@ +%TAG !o! tag:ben-kiki.org,2000: +--- +- !local foo +- !!str bar +- !o!type baz diff --git a/src/ext_depends/D-YAML/test/data/spec-08-05.test_loader_skip b/src/ext_depends/D-YAML/test/data/spec-08-05.test_loader_skip new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-05.test_loader_skip diff --git a/src/ext_depends/D-YAML/test/data/spec-08-06.data b/src/ext_depends/D-YAML/test/data/spec-08-06.data new file mode 100644 index 0000000..8580010 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-06.data @@ -0,0 +1,5 @@ +%TAG !o! tag:ben-kiki.org,2000: +--- +- !$a!b foo +- !o! bar +- !h!type baz diff --git a/src/ext_depends/D-YAML/test/data/spec-08-06.error b/src/ext_depends/D-YAML/test/data/spec-08-06.error new file mode 100644 index 0000000..fb76f42 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-06.error @@ -0,0 +1,4 @@ +ERROR: +- The !$a! looks like a handle. +- The !o! handle has no suffix. +- The !h! handle wasn't declared. diff --git a/src/ext_depends/D-YAML/test/data/spec-08-07.canonical b/src/ext_depends/D-YAML/test/data/spec-08-07.canonical new file mode 100644 index 0000000..e2f43d9 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-07.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!seq [ + !<tag:yaml.org,2002:str> "12", + !<tag:yaml.org,2002:int> "12", +# !<tag:yaml.org,2002:str> "12", + !<tag:yaml.org,2002:int> "12", +] diff --git a/src/ext_depends/D-YAML/test/data/spec-08-07.data b/src/ext_depends/D-YAML/test/data/spec-08-07.data new file mode 100644 index 0000000..98aa565 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-07.data @@ -0,0 +1,4 @@ +# Assuming conventional resolution: +- "12" +- 12 +- ! 12 diff --git a/src/ext_depends/D-YAML/test/data/spec-08-08.canonical b/src/ext_depends/D-YAML/test/data/spec-08-08.canonical new file mode 100644 index 0000000..d3f8b1a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-08.canonical @@ -0,0 +1,15 @@ +%YAML 1.1 +--- +!!map { + ? !!str "foo" + : !!str "bar baz" +} +%YAML 1.1 +--- +!!str "foo bar" +%YAML 1.1 +--- +!!str "foo bar" +%YAML 1.1 +--- +!!str "foo\n" diff --git a/src/ext_depends/D-YAML/test/data/spec-08-08.data b/src/ext_depends/D-YAML/test/data/spec-08-08.data new file mode 100644 index 0000000..757a93d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-08.data @@ -0,0 +1,13 @@ +--- +foo: + "bar + baz" +--- +"foo + bar" +--- +foo + bar +--- | + foo +... diff --git a/src/ext_depends/D-YAML/test/data/spec-08-09.canonical b/src/ext_depends/D-YAML/test/data/spec-08-09.canonical new file mode 100644 index 0000000..3805daf --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-09.canonical @@ -0,0 +1,21 @@ +%YAML 1.1 +--- !!map { + ? !!str "scalars" : !!map { + ? !!str "plain" + : !!str "some text", + ? !!str "quoted" + : !!map { + ? !!str "single" + : !!str "some text", + ? !!str "double" + : !!str "some text" + } }, + ? !!str "collections" : !!map { + ? !!str "sequence" : !!seq [ + !!str "entry", + !!map { + ? !!str "key" : !!str "value" + } ], + ? !!str "mapping" : !!map { + ? !!str "key" : !!str "value" +} } } diff --git a/src/ext_depends/D-YAML/test/data/spec-08-09.data b/src/ext_depends/D-YAML/test/data/spec-08-09.data new file mode 100644 index 0000000..69da042 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-09.data @@ -0,0 +1,11 @@ +--- +scalars: + plain: !!str some text + quoted: + single: 'some text' + double: "some text" +collections: + sequence: !!seq [ !!str entry, + # Mapping entry: + key: value ] + mapping: { key: value } diff --git a/src/ext_depends/D-YAML/test/data/spec-08-10.canonical b/src/ext_depends/D-YAML/test/data/spec-08-10.canonical new file mode 100644 index 0000000..8281c5e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-10.canonical @@ -0,0 +1,23 @@ +%YAML 1.1 +--- +!!map { + ? !!str "block styles" : !!map { + ? !!str "scalars" : !!map { + ? !!str "literal" + : !!str "#!/usr/bin/perl\n\ + print \"Hello, + world!\\n\";\n", + ? !!str "folded" + : !!str "This sentence + is false.\n" + }, + ? !!str "collections" : !!map { + ? !!str "sequence" : !!seq [ + !!str "entry", + !!map { + ? !!str "key" : !!str "value" + } + ], + ? !!str "mapping" : !!map { + ? !!str "key" : !!str "value" +} } } } diff --git a/src/ext_depends/D-YAML/test/data/spec-08-10.data b/src/ext_depends/D-YAML/test/data/spec-08-10.data new file mode 100644 index 0000000..72acc56 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-10.data @@ -0,0 +1,15 @@ +block styles: + scalars: + literal: !!str | + #!/usr/bin/perl + print "Hello, world!\n"; + folded: > + This sentence + is false. + collections: !!map + sequence: !!seq # Entry: + - entry # Plain + # Mapping entry: + - key: value + mapping: + key: value diff --git a/src/ext_depends/D-YAML/test/data/spec-08-11.canonical b/src/ext_depends/D-YAML/test/data/spec-08-11.canonical new file mode 100644 index 0000000..dd6f76e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-11.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!map { + ? !!str "First occurrence" + : &A !!str "Value", + ? !!str "Second occurrence" + : *A +} diff --git a/src/ext_depends/D-YAML/test/data/spec-08-11.data b/src/ext_depends/D-YAML/test/data/spec-08-11.data new file mode 100644 index 0000000..600d179 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-11.data @@ -0,0 +1,2 @@ +First occurrence: &anchor Value +Second occurrence: *anchor diff --git a/src/ext_depends/D-YAML/test/data/spec-08-12.canonical b/src/ext_depends/D-YAML/test/data/spec-08-12.canonical new file mode 100644 index 0000000..93899f4 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-12.canonical @@ -0,0 +1,10 @@ +%YAML 1.1 +--- +!!seq [ + !!str "Without properties", + &A !!str "Anchored", + !!str "Tagged", + *A, + !!str "", + !!str "", +] diff --git a/src/ext_depends/D-YAML/test/data/spec-08-12.data b/src/ext_depends/D-YAML/test/data/spec-08-12.data new file mode 100644 index 0000000..3d4c6b7 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-12.data @@ -0,0 +1,8 @@ +[ + Without properties, + &anchor "Anchored", + !!str 'Tagged', + *anchor, # Alias node + !!str , # Empty plain scalar + '', # Empty plain scalar +] diff --git a/src/ext_depends/D-YAML/test/data/spec-08-13.canonical b/src/ext_depends/D-YAML/test/data/spec-08-13.canonical new file mode 100644 index 0000000..618bb7b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-13.canonical @@ -0,0 +1,10 @@ +%YAML 1.1 +--- +!!map { + ? !!str "foo" +# : !!str "", +# ? !!str "" + : !!null "", + ? !!null "" + : !!str "bar", +} diff --git a/src/ext_depends/D-YAML/test/data/spec-08-13.data b/src/ext_depends/D-YAML/test/data/spec-08-13.data new file mode 100644 index 0000000..ebe663a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-13.data @@ -0,0 +1,4 @@ +{ + ? foo :, + ? : bar, +} diff --git a/src/ext_depends/D-YAML/test/data/spec-08-13.skip-ext b/src/ext_depends/D-YAML/test/data/spec-08-13.skip-ext new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-13.skip-ext diff --git a/src/ext_depends/D-YAML/test/data/spec-08-14.canonical b/src/ext_depends/D-YAML/test/data/spec-08-14.canonical new file mode 100644 index 0000000..11db439 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-14.canonical @@ -0,0 +1,10 @@ +%YAML 1.1 +--- +!!seq [ + !!str "flow in block", + !!str "Block scalar\n", + !!map { + ? !!str "foo" + : !!str "bar" + } +] diff --git a/src/ext_depends/D-YAML/test/data/spec-08-14.data b/src/ext_depends/D-YAML/test/data/spec-08-14.data new file mode 100644 index 0000000..2fbb1f7 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-14.data @@ -0,0 +1,5 @@ +- "flow in block" +- > + Block scalar +- !!map # Block collection + foo : bar diff --git a/src/ext_depends/D-YAML/test/data/spec-08-15.canonical b/src/ext_depends/D-YAML/test/data/spec-08-15.canonical new file mode 100644 index 0000000..76f028e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-15.canonical @@ -0,0 +1,11 @@ +%YAML 1.1 +--- +!!seq [ + !!null "", + !!map { + ? !!str "foo" + : !!null "", + ? !!null "" + : !!str "bar", + } +] diff --git a/src/ext_depends/D-YAML/test/data/spec-08-15.data b/src/ext_depends/D-YAML/test/data/spec-08-15.data new file mode 100644 index 0000000..7c86bcf --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-08-15.data @@ -0,0 +1,5 @@ +- # Empty plain scalar +- ? foo + : + ? + : bar diff --git a/src/ext_depends/D-YAML/test/data/spec-09-01.canonical b/src/ext_depends/D-YAML/test/data/spec-09-01.canonical new file mode 100644 index 0000000..e71a548 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-01.canonical @@ -0,0 +1,11 @@ +%YAML 1.1 +--- +!!map { + ? !!str "simple key" + : !!map { + ? !!str "also simple" + : !!str "value", + ? !!str "not a simple key" + : !!str "any value" + } +} diff --git a/src/ext_depends/D-YAML/test/data/spec-09-01.data b/src/ext_depends/D-YAML/test/data/spec-09-01.data new file mode 100644 index 0000000..9e83eaf --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-01.data @@ -0,0 +1,6 @@ +"simple key" : { + "also simple" : value, + ? "not a + simple key" : "any + value" +} diff --git a/src/ext_depends/D-YAML/test/data/spec-09-02.canonical b/src/ext_depends/D-YAML/test/data/spec-09-02.canonical new file mode 100644 index 0000000..6f8f41a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-02.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!str "as space \ + trimmed\n\ + specific\L\n\ + escaped\t\n\ + none" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-02.data b/src/ext_depends/D-YAML/test/data/spec-09-02.data new file mode 100644 index 0000000..d84883d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-02.data @@ -0,0 +1,6 @@ + "as space + trimmed + + specific
+ escaped \
+ none" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-03.canonical b/src/ext_depends/D-YAML/test/data/spec-09-03.canonical new file mode 100644 index 0000000..658c6df --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-03.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!seq [ + !!str " last", + !!str " last", + !!str " \tfirst last", +] diff --git a/src/ext_depends/D-YAML/test/data/spec-09-03.data b/src/ext_depends/D-YAML/test/data/spec-09-03.data new file mode 100644 index 0000000..e0b914d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-03.data @@ -0,0 +1,6 @@ +- " + last" +- " + last" +- " first + last" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-04.canonical b/src/ext_depends/D-YAML/test/data/spec-09-04.canonical new file mode 100644 index 0000000..fa46632 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-04.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!str "first \ + inner 1 \ + inner 2 \ + last" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-04.data b/src/ext_depends/D-YAML/test/data/spec-09-04.data new file mode 100644 index 0000000..313a91b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-04.data @@ -0,0 +1,4 @@ + "first + inner 1 + \ inner 2 \ + last" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-05.canonical b/src/ext_depends/D-YAML/test/data/spec-09-05.canonical new file mode 100644 index 0000000..24d1052 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-05.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!seq [ + !!str "first ", + !!str "first\nlast", + !!str "first inner \tlast", +] diff --git a/src/ext_depends/D-YAML/test/data/spec-09-05.data b/src/ext_depends/D-YAML/test/data/spec-09-05.data new file mode 100644 index 0000000..624c30e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-05.data @@ -0,0 +1,8 @@ +- "first + " +- "first + + last" +- "first + inner + \ last" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-06.canonical b/src/ext_depends/D-YAML/test/data/spec-09-06.canonical new file mode 100644 index 0000000..5028772 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-06.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "here's to \"quotes\"" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-06.data b/src/ext_depends/D-YAML/test/data/spec-09-06.data new file mode 100644 index 0000000..b038078 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-06.data @@ -0,0 +1 @@ + 'here''s to "quotes"' diff --git a/src/ext_depends/D-YAML/test/data/spec-09-07.canonical b/src/ext_depends/D-YAML/test/data/spec-09-07.canonical new file mode 100644 index 0000000..e71a548 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-07.canonical @@ -0,0 +1,11 @@ +%YAML 1.1 +--- +!!map { + ? !!str "simple key" + : !!map { + ? !!str "also simple" + : !!str "value", + ? !!str "not a simple key" + : !!str "any value" + } +} diff --git a/src/ext_depends/D-YAML/test/data/spec-09-07.data b/src/ext_depends/D-YAML/test/data/spec-09-07.data new file mode 100644 index 0000000..755b54a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-07.data @@ -0,0 +1,6 @@ +'simple key' : { + 'also simple' : value, + ? 'not a + simple key' : 'any + value' +} diff --git a/src/ext_depends/D-YAML/test/data/spec-09-08.canonical b/src/ext_depends/D-YAML/test/data/spec-09-08.canonical new file mode 100644 index 0000000..06abdb5 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-08.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!str "as space \ + trimmed\n\ + specific\L\n\ + none" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-08.data b/src/ext_depends/D-YAML/test/data/spec-09-08.data new file mode 100644 index 0000000..aa4d458 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-08.data @@ -0,0 +1 @@ + 'as space
trimmed
specific
none' diff --git a/src/ext_depends/D-YAML/test/data/spec-09-09.canonical b/src/ext_depends/D-YAML/test/data/spec-09-09.canonical new file mode 100644 index 0000000..658c6df --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-09.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!seq [ + !!str " last", + !!str " last", + !!str " \tfirst last", +] diff --git a/src/ext_depends/D-YAML/test/data/spec-09-09.data b/src/ext_depends/D-YAML/test/data/spec-09-09.data new file mode 100644 index 0000000..52171df --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-09.data @@ -0,0 +1,6 @@ +- ' + last' +- ' + last' +- ' first + last' diff --git a/src/ext_depends/D-YAML/test/data/spec-09-10.canonical b/src/ext_depends/D-YAML/test/data/spec-09-10.canonical new file mode 100644 index 0000000..2028d04 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-10.canonical @@ -0,0 +1,5 @@ +%YAML 1.1 +--- +!!str "first \ + inner \ + last" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-10.data b/src/ext_depends/D-YAML/test/data/spec-09-10.data new file mode 100644 index 0000000..0e41449 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-10.data @@ -0,0 +1,3 @@ + 'first + inner + last' diff --git a/src/ext_depends/D-YAML/test/data/spec-09-11.canonical b/src/ext_depends/D-YAML/test/data/spec-09-11.canonical new file mode 100644 index 0000000..4eb222c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-11.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!seq [ + !!str "first ", + !!str "first\nlast", +] diff --git a/src/ext_depends/D-YAML/test/data/spec-09-11.data b/src/ext_depends/D-YAML/test/data/spec-09-11.data new file mode 100644 index 0000000..5efa873 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-11.data @@ -0,0 +1,5 @@ +- 'first + ' +- 'first + + last' diff --git a/src/ext_depends/D-YAML/test/data/spec-09-12.canonical b/src/ext_depends/D-YAML/test/data/spec-09-12.canonical new file mode 100644 index 0000000..d8e6dce --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-12.canonical @@ -0,0 +1,12 @@ +%YAML 1.1 +--- +!!seq [ + !!str "::std::vector", + !!str "Up, up, and away!", + !!int "-123", + !!seq [ + !!str "::std::vector", + !!str "Up, up, and away!", + !!int "-123", + ] +] diff --git a/src/ext_depends/D-YAML/test/data/spec-09-12.data b/src/ext_depends/D-YAML/test/data/spec-09-12.data new file mode 100644 index 0000000..b9a3ac5 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-12.data @@ -0,0 +1,8 @@ +# Outside flow collection: +- ::std::vector +- Up, up, and away! +- -123 +# Inside flow collection: +- [ '::std::vector', + "Up, up, and away!", + -123 ] diff --git a/src/ext_depends/D-YAML/test/data/spec-09-13.canonical b/src/ext_depends/D-YAML/test/data/spec-09-13.canonical new file mode 100644 index 0000000..e71a548 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-13.canonical @@ -0,0 +1,11 @@ +%YAML 1.1 +--- +!!map { + ? !!str "simple key" + : !!map { + ? !!str "also simple" + : !!str "value", + ? !!str "not a simple key" + : !!str "any value" + } +} diff --git a/src/ext_depends/D-YAML/test/data/spec-09-13.data b/src/ext_depends/D-YAML/test/data/spec-09-13.data new file mode 100644 index 0000000..b156386 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-13.data @@ -0,0 +1,6 @@ +simple key : { + also simple : value, + ? not a + simple key : any + value +} diff --git a/src/ext_depends/D-YAML/test/data/spec-09-14.data b/src/ext_depends/D-YAML/test/data/spec-09-14.data new file mode 100644 index 0000000..97f2316 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-14.data @@ -0,0 +1,14 @@ +--- +--- ||| : foo +... >>>: bar +--- +[ +--- +, +... , +{ +--- : +... # Nested +} +] +... diff --git a/src/ext_depends/D-YAML/test/data/spec-09-14.error b/src/ext_depends/D-YAML/test/data/spec-09-14.error new file mode 100644 index 0000000..9f3db7b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-14.error @@ -0,0 +1,6 @@ +ERROR: + The --- and ... document + start and end markers must + not be specified as the + first content line of a + non-indented plain scalar. diff --git a/src/ext_depends/D-YAML/test/data/spec-09-15.canonical b/src/ext_depends/D-YAML/test/data/spec-09-15.canonical new file mode 100644 index 0000000..df02040 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-15.canonical @@ -0,0 +1,18 @@ +%YAML 1.1 +--- +!!map { + ? !!str "---" + : !!str "foo", + ? !!str "..." + : !!str "bar" +} +%YAML 1.1 +--- +!!seq [ + !!str "---", + !!str "...", + !!map { + ? !!str "---" + : !!str "..." + } +] diff --git a/src/ext_depends/D-YAML/test/data/spec-09-15.data b/src/ext_depends/D-YAML/test/data/spec-09-15.data new file mode 100644 index 0000000..e6863b0 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-15.data @@ -0,0 +1,13 @@ +--- +"---" : foo +...: bar +--- +[ +---, +..., +{ +? --- +: ... +} +] +... diff --git a/src/ext_depends/D-YAML/test/data/spec-09-16.canonical b/src/ext_depends/D-YAML/test/data/spec-09-16.canonical new file mode 100644 index 0000000..06abdb5 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-16.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!str "as space \ + trimmed\n\ + specific\L\n\ + none" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-16.data b/src/ext_depends/D-YAML/test/data/spec-09-16.data new file mode 100644 index 0000000..473beb9 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-16.data @@ -0,0 +1,3 @@ +# Tabs are confusing: +# as space/trimmed/specific/none + as space
trimmed
specific
none diff --git a/src/ext_depends/D-YAML/test/data/spec-09-17.canonical b/src/ext_depends/D-YAML/test/data/spec-09-17.canonical new file mode 100644 index 0000000..68cb70d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-17.canonical @@ -0,0 +1,4 @@ +%YAML 1.1 +--- +!!str "first line\n\ + more line" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-17.data b/src/ext_depends/D-YAML/test/data/spec-09-17.data new file mode 100644 index 0000000..97bc46c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-17.data @@ -0,0 +1,3 @@ + first line + + more line diff --git a/src/ext_depends/D-YAML/test/data/spec-09-18.canonical b/src/ext_depends/D-YAML/test/data/spec-09-18.canonical new file mode 100644 index 0000000..f21428f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-18.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!seq [ + !!str "literal\n", + !!str " folded\n", + !!str "keep\n\n", + !!str " strip", +] diff --git a/src/ext_depends/D-YAML/test/data/spec-09-18.data b/src/ext_depends/D-YAML/test/data/spec-09-18.data new file mode 100644 index 0000000..68c5d7c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-18.data @@ -0,0 +1,9 @@ +- | # Just the style + literal +- >1 # Indentation indicator + folded +- |+ # Chomping indicator + keep + +- >-1 # Both indicators + strip diff --git a/src/ext_depends/D-YAML/test/data/spec-09-19.canonical b/src/ext_depends/D-YAML/test/data/spec-09-19.canonical new file mode 100644 index 0000000..3e828d7 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-19.canonical @@ -0,0 +1,6 @@ +%YAML 1.1 +--- +!!seq [ + !!str "literal\n", + !!str "folded\n", +] diff --git a/src/ext_depends/D-YAML/test/data/spec-09-19.data b/src/ext_depends/D-YAML/test/data/spec-09-19.data new file mode 100644 index 0000000..f0e589d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-19.data @@ -0,0 +1,4 @@ +- | + literal +- > + folded diff --git a/src/ext_depends/D-YAML/test/data/spec-09-20.canonical b/src/ext_depends/D-YAML/test/data/spec-09-20.canonical new file mode 100644 index 0000000..d03bef5 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-20.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!seq [ + !!str "detected\n", + !!str "\n\n# detected\n", + !!str " explicit\n", + !!str "\t\ndetected\n", +] diff --git a/src/ext_depends/D-YAML/test/data/spec-09-20.data b/src/ext_depends/D-YAML/test/data/spec-09-20.data new file mode 100644 index 0000000..39bee04 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-20.data @@ -0,0 +1,11 @@ +- | + detected +- > + + + # detected +- |1 + explicit +- > + + detected diff --git a/src/ext_depends/D-YAML/test/data/spec-09-20.skip-ext b/src/ext_depends/D-YAML/test/data/spec-09-20.skip-ext new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-20.skip-ext diff --git a/src/ext_depends/D-YAML/test/data/spec-09-21.data b/src/ext_depends/D-YAML/test/data/spec-09-21.data new file mode 100644 index 0000000..0fdd14f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-21.data @@ -0,0 +1,8 @@ +- | + + text +- > + text + text +- |1 + text diff --git a/src/ext_depends/D-YAML/test/data/spec-09-21.error b/src/ext_depends/D-YAML/test/data/spec-09-21.error new file mode 100644 index 0000000..1379ca5 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-21.error @@ -0,0 +1,7 @@ +ERROR: +- A leading all-space line must + not have too many spaces. +- A following text line must + not be less indented. +- The text is less indented + than the indicated level. diff --git a/src/ext_depends/D-YAML/test/data/spec-09-22.canonical b/src/ext_depends/D-YAML/test/data/spec-09-22.canonical new file mode 100644 index 0000000..c1bbcd2 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-22.canonical @@ -0,0 +1,10 @@ +%YAML 1.1 +--- +!!map { + ? !!str "strip" + : !!str "text", + ? !!str "clip" + : !!str "text\n", + ? !!str "keep" + : !!str "text\L", +} diff --git a/src/ext_depends/D-YAML/test/data/spec-09-22.data b/src/ext_depends/D-YAML/test/data/spec-09-22.data new file mode 100644 index 0000000..0dd51eb --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-22.data @@ -0,0 +1,4 @@ +strip: |- + text
clip: | + text
keep: |+ + text
\ No newline at end of file diff --git a/src/ext_depends/D-YAML/test/data/spec-09-23.canonical b/src/ext_depends/D-YAML/test/data/spec-09-23.canonical new file mode 100644 index 0000000..c4444ca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-23.canonical @@ -0,0 +1,10 @@ +%YAML 1.1 +--- +!!map { + ? !!str "strip" + : !!str "# text", + ? !!str "clip" + : !!str "# text\n", + ? !!str "keep" + : !!str "# text\L\n", +} diff --git a/src/ext_depends/D-YAML/test/data/spec-09-23.data b/src/ext_depends/D-YAML/test/data/spec-09-23.data new file mode 100644 index 0000000..8972d2b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-23.data @@ -0,0 +1,11 @@ + # Strip + # Comments: +strip: |- + # text
# Clip + # comments: +
clip: | + # text
# Keep + # comments: +
keep: |+ + # text
# Trail + # comments. diff --git a/src/ext_depends/D-YAML/test/data/spec-09-24.canonical b/src/ext_depends/D-YAML/test/data/spec-09-24.canonical new file mode 100644 index 0000000..45a99b0 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-24.canonical @@ -0,0 +1,10 @@ +%YAML 1.1 +--- +!!map { + ? !!str "strip" + : !!str "", + ? !!str "clip" + : !!str "", + ? !!str "keep" + : !!str "\n", +} diff --git a/src/ext_depends/D-YAML/test/data/spec-09-24.data b/src/ext_depends/D-YAML/test/data/spec-09-24.data new file mode 100644 index 0000000..de0b64b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-24.data @@ -0,0 +1,6 @@ +strip: >- + +clip: > + +keep: |+ + diff --git a/src/ext_depends/D-YAML/test/data/spec-09-25.canonical b/src/ext_depends/D-YAML/test/data/spec-09-25.canonical new file mode 100644 index 0000000..9d2327b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-25.canonical @@ -0,0 +1,4 @@ +%YAML 1.1 +--- +!!str "literal\n\ + \ttext\n" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-25.data b/src/ext_depends/D-YAML/test/data/spec-09-25.data new file mode 100644 index 0000000..f6303a1 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-25.data @@ -0,0 +1,3 @@ +| # Simple block scalar + literal + text diff --git a/src/ext_depends/D-YAML/test/data/spec-09-26.canonical b/src/ext_depends/D-YAML/test/data/spec-09-26.canonical new file mode 100644 index 0000000..3029a11 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-26.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "\n\nliteral\n\ntext\n" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-26.data b/src/ext_depends/D-YAML/test/data/spec-09-26.data new file mode 100644 index 0000000..f28555a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-26.data @@ -0,0 +1,8 @@ +| + + + literal + + text + + # Comment diff --git a/src/ext_depends/D-YAML/test/data/spec-09-27.canonical b/src/ext_depends/D-YAML/test/data/spec-09-27.canonical new file mode 100644 index 0000000..3029a11 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-27.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "\n\nliteral\n\ntext\n" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-27.data b/src/ext_depends/D-YAML/test/data/spec-09-27.data new file mode 100644 index 0000000..f28555a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-27.data @@ -0,0 +1,8 @@ +| + + + literal + + text + + # Comment diff --git a/src/ext_depends/D-YAML/test/data/spec-09-28.canonical b/src/ext_depends/D-YAML/test/data/spec-09-28.canonical new file mode 100644 index 0000000..3029a11 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-28.canonical @@ -0,0 +1,3 @@ +%YAML 1.1 +--- +!!str "\n\nliteral\n\ntext\n" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-28.data b/src/ext_depends/D-YAML/test/data/spec-09-28.data new file mode 100644 index 0000000..f28555a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-28.data @@ -0,0 +1,8 @@ +| + + + literal + + text + + # Comment diff --git a/src/ext_depends/D-YAML/test/data/spec-09-29.canonical b/src/ext_depends/D-YAML/test/data/spec-09-29.canonical new file mode 100644 index 0000000..0980789 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-29.canonical @@ -0,0 +1,4 @@ +%YAML 1.1 +--- +!!str "folded text\n\ + \tlines\n" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-29.data b/src/ext_depends/D-YAML/test/data/spec-09-29.data new file mode 100644 index 0000000..82e611f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-29.data @@ -0,0 +1,4 @@ +> # Simple folded scalar + folded + text + lines diff --git a/src/ext_depends/D-YAML/test/data/spec-09-30.canonical b/src/ext_depends/D-YAML/test/data/spec-09-30.canonical new file mode 100644 index 0000000..fc37db1 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-30.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!str "folded line\n\ + next line\n\n\ + \ * bullet\n\ + \ * list\n\n\ + last line\n" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-30.data b/src/ext_depends/D-YAML/test/data/spec-09-30.data new file mode 100644 index 0000000..a4d8c36 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-30.data @@ -0,0 +1,14 @@ +> + folded + line + + next + line + + * bullet + * list + + last + line + +# Comment diff --git a/src/ext_depends/D-YAML/test/data/spec-09-31.canonical b/src/ext_depends/D-YAML/test/data/spec-09-31.canonical new file mode 100644 index 0000000..fc37db1 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-31.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!str "folded line\n\ + next line\n\n\ + \ * bullet\n\ + \ * list\n\n\ + last line\n" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-31.data b/src/ext_depends/D-YAML/test/data/spec-09-31.data new file mode 100644 index 0000000..a4d8c36 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-31.data @@ -0,0 +1,14 @@ +> + folded + line + + next + line + + * bullet + * list + + last + line + +# Comment diff --git a/src/ext_depends/D-YAML/test/data/spec-09-32.canonical b/src/ext_depends/D-YAML/test/data/spec-09-32.canonical new file mode 100644 index 0000000..fc37db1 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-32.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!str "folded line\n\ + next line\n\n\ + \ * bullet\n\ + \ * list\n\n\ + last line\n" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-32.data b/src/ext_depends/D-YAML/test/data/spec-09-32.data new file mode 100644 index 0000000..a4d8c36 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-32.data @@ -0,0 +1,14 @@ +> + folded + line + + next + line + + * bullet + * list + + last + line + +# Comment diff --git a/src/ext_depends/D-YAML/test/data/spec-09-33.canonical b/src/ext_depends/D-YAML/test/data/spec-09-33.canonical new file mode 100644 index 0000000..fc37db1 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-33.canonical @@ -0,0 +1,7 @@ +%YAML 1.1 +--- +!!str "folded line\n\ + next line\n\n\ + \ * bullet\n\ + \ * list\n\n\ + last line\n" diff --git a/src/ext_depends/D-YAML/test/data/spec-09-33.data b/src/ext_depends/D-YAML/test/data/spec-09-33.data new file mode 100644 index 0000000..a4d8c36 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-09-33.data @@ -0,0 +1,14 @@ +> + folded + line + + next + line + + * bullet + * list + + last + line + +# Comment diff --git a/src/ext_depends/D-YAML/test/data/spec-10-01.canonical b/src/ext_depends/D-YAML/test/data/spec-10-01.canonical new file mode 100644 index 0000000..d08cdd4 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-01.canonical @@ -0,0 +1,12 @@ +%YAML 1.1 +--- +!!seq [ + !!seq [ + !!str "inner", + !!str "inner", + ], + !!seq [ + !!str "inner", + !!str "last", + ], +] diff --git a/src/ext_depends/D-YAML/test/data/spec-10-01.data b/src/ext_depends/D-YAML/test/data/spec-10-01.data new file mode 100644 index 0000000..e668d38 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-01.data @@ -0,0 +1,2 @@ +- [ inner, inner, ] +- [inner,last] diff --git a/src/ext_depends/D-YAML/test/data/spec-10-02.canonical b/src/ext_depends/D-YAML/test/data/spec-10-02.canonical new file mode 100644 index 0000000..82fe0d9 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-02.canonical @@ -0,0 +1,14 @@ +%YAML 1.1 +--- +!!seq [ + !!str "double quoted", + !!str "single quoted", + !!str "plain text", + !!seq [ + !!str "nested", + ], + !!map { + ? !!str "single" + : !!str "pair" + } +] diff --git a/src/ext_depends/D-YAML/test/data/spec-10-02.data b/src/ext_depends/D-YAML/test/data/spec-10-02.data new file mode 100644 index 0000000..3b23351 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-02.data @@ -0,0 +1,8 @@ +[ +"double + quoted", 'single + quoted', +plain + text, [ nested ], +single: pair , +] diff --git a/src/ext_depends/D-YAML/test/data/spec-10-03.canonical b/src/ext_depends/D-YAML/test/data/spec-10-03.canonical new file mode 100644 index 0000000..1443395 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-03.canonical @@ -0,0 +1,12 @@ +%YAML 1.1 +--- +!!map { + ? !!str "block" + : !!seq [ + !!str "one", + !!map { + ? !!str "two" + : !!str "three" + } + ] +} diff --git a/src/ext_depends/D-YAML/test/data/spec-10-03.data b/src/ext_depends/D-YAML/test/data/spec-10-03.data new file mode 100644 index 0000000..9e15f83 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-03.data @@ -0,0 +1,4 @@ +block: # Block + # sequence +- one +- two : three diff --git a/src/ext_depends/D-YAML/test/data/spec-10-04.canonical b/src/ext_depends/D-YAML/test/data/spec-10-04.canonical new file mode 100644 index 0000000..ae486a3 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-04.canonical @@ -0,0 +1,11 @@ +%YAML 1.1 +--- +!!map { + ? !!str "block" + : !!seq [ + !!str "one", + !!seq [ + !!str "two" + ] + ] +} diff --git a/src/ext_depends/D-YAML/test/data/spec-10-04.data b/src/ext_depends/D-YAML/test/data/spec-10-04.data new file mode 100644 index 0000000..2905b0d --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-04.data @@ -0,0 +1,4 @@ +block: +- one +- + - two diff --git a/src/ext_depends/D-YAML/test/data/spec-10-05.canonical b/src/ext_depends/D-YAML/test/data/spec-10-05.canonical new file mode 100644 index 0000000..07cc0c9 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-05.canonical @@ -0,0 +1,14 @@ +%YAML 1.1 +--- +!!seq [ + !!null "", + !!str "block node\n", + !!seq [ + !!str "one", + !!str "two", + ], + !!map { + ? !!str "one" + : !!str "two", + } +] diff --git a/src/ext_depends/D-YAML/test/data/spec-10-05.data b/src/ext_depends/D-YAML/test/data/spec-10-05.data new file mode 100644 index 0000000..f19a99e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-05.data @@ -0,0 +1,7 @@ +- # Empty +- | + block node +- - one # in-line + - two # sequence +- one: two # in-line + # mapping diff --git a/src/ext_depends/D-YAML/test/data/spec-10-06.canonical b/src/ext_depends/D-YAML/test/data/spec-10-06.canonical new file mode 100644 index 0000000..d9986c2 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-06.canonical @@ -0,0 +1,16 @@ +%YAML 1.1 +--- +!!seq [ + !!map { + ? !!str "inner" + : !!str "entry", + ? !!str "also" + : !!str "inner" + }, + !!map { + ? !!str "inner" + : !!str "entry", + ? !!str "last" + : !!str "entry" + } +] diff --git a/src/ext_depends/D-YAML/test/data/spec-10-06.data b/src/ext_depends/D-YAML/test/data/spec-10-06.data new file mode 100644 index 0000000..860ba25 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-06.data @@ -0,0 +1,2 @@ +- { inner : entry , also: inner , } +- {inner: entry,last : entry} diff --git a/src/ext_depends/D-YAML/test/data/spec-10-07.canonical b/src/ext_depends/D-YAML/test/data/spec-10-07.canonical new file mode 100644 index 0000000..ec74230 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-07.canonical @@ -0,0 +1,16 @@ +%YAML 1.1 +--- +!!map { + ? !!null "" + : !!str "value", + ? !!str "explicit key" + : !!str "value", + ? !!str "simple key" + : !!str "value", + ? !!seq [ + !!str "collection", + !!str "simple", + !!str "key" + ] + : !!str "value" +} diff --git a/src/ext_depends/D-YAML/test/data/spec-10-07.data b/src/ext_depends/D-YAML/test/data/spec-10-07.data new file mode 100644 index 0000000..ff943fb --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-07.data @@ -0,0 +1,7 @@ +{ +? : value, # Empty key +? explicit + key: value, +simple key : value, +[ collection, simple, key ]: value +} diff --git a/src/ext_depends/D-YAML/test/data/spec-10-08.data b/src/ext_depends/D-YAML/test/data/spec-10-08.data new file mode 100644 index 0000000..55bd788 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-08.data @@ -0,0 +1,5 @@ +{ +multi-line + simple key : value, +very long ...................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................(>1KB)................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... key: value +} diff --git a/src/ext_depends/D-YAML/test/data/spec-10-08.error b/src/ext_depends/D-YAML/test/data/spec-10-08.error new file mode 100644 index 0000000..3979e1f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-08.error @@ -0,0 +1,5 @@ +ERROR: +- A simple key is restricted + to only one line. +- A simple key must not be + longer than 1024 characters. diff --git a/src/ext_depends/D-YAML/test/data/spec-10-09.canonical b/src/ext_depends/D-YAML/test/data/spec-10-09.canonical new file mode 100644 index 0000000..4d9827b --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-09.canonical @@ -0,0 +1,8 @@ +%YAML 1.1 +--- +!!map { + ? !!str "key" + : !!str "value", + ? !!str "empty" + : !!null "", +} diff --git a/src/ext_depends/D-YAML/test/data/spec-10-09.data b/src/ext_depends/D-YAML/test/data/spec-10-09.data new file mode 100644 index 0000000..4d55e21 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-09.data @@ -0,0 +1,4 @@ +{ +key : value, +empty: # empty value↓ +} diff --git a/src/ext_depends/D-YAML/test/data/spec-10-10.canonical b/src/ext_depends/D-YAML/test/data/spec-10-10.canonical new file mode 100644 index 0000000..016fb64 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-10.canonical @@ -0,0 +1,16 @@ +%YAML 1.1 +--- +!!map { + ? !!str "explicit key1" + : !!str "explicit value", + ? !!str "explicit key2" + : !!null "", + ? !!str "explicit key3" + : !!null "", + ? !!str "simple key1" + : !!str "explicit value", + ? !!str "simple key2" + : !!null "", + ? !!str "simple key3" + : !!null "", +} diff --git a/src/ext_depends/D-YAML/test/data/spec-10-10.data b/src/ext_depends/D-YAML/test/data/spec-10-10.data new file mode 100644 index 0000000..0888b05 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-10.data @@ -0,0 +1,8 @@ +{ +? explicit key1 : explicit value, +? explicit key2 : , # Explicit empty +? explicit key3, # Empty value +simple key1 : explicit value, +simple key2 : , # Explicit empty +simple key3, # Empty value +} diff --git a/src/ext_depends/D-YAML/test/data/spec-10-11.canonical b/src/ext_depends/D-YAML/test/data/spec-10-11.canonical new file mode 100644 index 0000000..7309544 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-11.canonical @@ -0,0 +1,24 @@ +%YAML 1.1 +--- +!!seq [ + !!map { + ? !!str "explicit key1" + : !!str "explicit value", + }, + !!map { + ? !!str "explicit key2" + : !!null "", + }, + !!map { + ? !!str "explicit key3" + : !!null "", + }, + !!map { + ? !!str "simple key1" + : !!str "explicit value", + }, + !!map { + ? !!str "simple key2" + : !!null "", + }, +] diff --git a/src/ext_depends/D-YAML/test/data/spec-10-11.data b/src/ext_depends/D-YAML/test/data/spec-10-11.data new file mode 100644 index 0000000..9f05568 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-11.data @@ -0,0 +1,7 @@ +[ +? explicit key1 : explicit value, +? explicit key2 : , # Explicit empty +? explicit key3, # Implicit empty +simple key1 : explicit value, +simple key2 : , # Explicit empty +] diff --git a/src/ext_depends/D-YAML/test/data/spec-10-12.canonical b/src/ext_depends/D-YAML/test/data/spec-10-12.canonical new file mode 100644 index 0000000..a95dd40 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-12.canonical @@ -0,0 +1,9 @@ +%YAML 1.1 +--- +!!map { + ? !!str "block" + : !!map { + ? !!str "key" + : !!str "value" + } +} diff --git a/src/ext_depends/D-YAML/test/data/spec-10-12.data b/src/ext_depends/D-YAML/test/data/spec-10-12.data new file mode 100644 index 0000000..5521443 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-12.data @@ -0,0 +1,3 @@ +block: # Block + # mapping + key: value diff --git a/src/ext_depends/D-YAML/test/data/spec-10-13.canonical b/src/ext_depends/D-YAML/test/data/spec-10-13.canonical new file mode 100644 index 0000000..e183c50 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-13.canonical @@ -0,0 +1,11 @@ +%YAML 1.1 +--- +!!map { + ? !!str "explicit key" + : !!null "", + ? !!str "block key\n" + : !!seq [ + !!str "one", + !!str "two", + ] +} diff --git a/src/ext_depends/D-YAML/test/data/spec-10-13.data b/src/ext_depends/D-YAML/test/data/spec-10-13.data new file mode 100644 index 0000000..b5b97db --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-13.data @@ -0,0 +1,5 @@ +? explicit key # implicit value +? | + block key +: - one # explicit in-line + - two # block value diff --git a/src/ext_depends/D-YAML/test/data/spec-10-14.canonical b/src/ext_depends/D-YAML/test/data/spec-10-14.canonical new file mode 100644 index 0000000..e87c880 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-14.canonical @@ -0,0 +1,11 @@ +%YAML 1.1 +--- +!!map { + ? !!str "plain key" + : !!null "", + ? !!str "quoted key" + : !!seq [ + !!str "one", + !!str "two", + ] +} diff --git a/src/ext_depends/D-YAML/test/data/spec-10-14.data b/src/ext_depends/D-YAML/test/data/spec-10-14.data new file mode 100644 index 0000000..7f5995c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-14.data @@ -0,0 +1,4 @@ +plain key: # empty value +"quoted key": +- one # explicit next-line +- two # block value diff --git a/src/ext_depends/D-YAML/test/data/spec-10-15.canonical b/src/ext_depends/D-YAML/test/data/spec-10-15.canonical new file mode 100644 index 0000000..85fbbd0 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-15.canonical @@ -0,0 +1,18 @@ +%YAML 1.1 +--- +!!seq [ + !!map { + ? !!str "sun" + : !!str "yellow" + }, + !!map { + ? !!map { + ? !!str "earth" + : !!str "blue" + } + : !!map { + ? !!str "moon" + : !!str "white" + } + } +] diff --git a/src/ext_depends/D-YAML/test/data/spec-10-15.data b/src/ext_depends/D-YAML/test/data/spec-10-15.data new file mode 100644 index 0000000..d675cfd --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/spec-10-15.data @@ -0,0 +1,3 @@ +- sun: yellow +- ? earth: blue + : moon: white diff --git a/src/ext_depends/D-YAML/test/data/str.data b/src/ext_depends/D-YAML/test/data/str.data new file mode 100644 index 0000000..7cbdb7c --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/str.data @@ -0,0 +1 @@ +- abcd diff --git a/src/ext_depends/D-YAML/test/data/str.detect b/src/ext_depends/D-YAML/test/data/str.detect new file mode 100644 index 0000000..7d5026f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/str.detect @@ -0,0 +1 @@ +tag:yaml.org,2002:str diff --git a/src/ext_depends/D-YAML/test/data/tags.events b/src/ext_depends/D-YAML/test/data/tags.events new file mode 100644 index 0000000..bb93dce --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/tags.events @@ -0,0 +1,12 @@ +- !StreamStart +- !DocumentStart +- !SequenceStart +- !Scalar { value: 'data' } +#- !Scalar { tag: '!', value: 'data' } +- !Scalar { tag: 'tag:yaml.org,2002:str', value: 'data' } +- !Scalar { tag: '!myfunnytag', value: 'data' } +- !Scalar { tag: '!my!ugly!tag', value: 'data' } +- !Scalar { tag: 'tag:my.domain.org,2002:data!? #', value: 'data' } +- !SequenceEnd +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/test_mark.marks b/src/ext_depends/D-YAML/test/data/test_mark.marks new file mode 100644 index 0000000..7b08ee4 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/test_mark.marks @@ -0,0 +1,38 @@ +--- +*The first line. +The last line. +--- +The first*line. +The last line. +--- +The first line.* +The last line. +--- +The first line. +*The last line. +--- +The first line. +The last*line. +--- +The first line. +The last line.* +--- +The first line. +*The selected line. +The last line. +--- +The first line. +The selected*line. +The last line. +--- +The first line. +The selected line.* +The last line. +--- +*The only line. +--- +The only*line. +--- +The only line.* +--- +Loooooooooooooooooooooooooooooooooooooooooooooong*Liiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiine diff --git a/src/ext_depends/D-YAML/test/data/timestamp-bugs.code b/src/ext_depends/D-YAML/test/data/timestamp-bugs.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/timestamp-bugs.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/timestamp-bugs.data b/src/ext_depends/D-YAML/test/data/timestamp-bugs.data new file mode 100644 index 0000000..503f1ce --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/timestamp-bugs.data @@ -0,0 +1,6 @@ +- 2001-12-14 21:59:43.1 -5:30 +- 2001-12-14 21:59:43.1 +5:30 +- 2001-12-14 21:59:43.00101 +- 2001-12-14 21:59:43+1 +- 2001-12-14 21:59:43-1:30 +- 2005-07-08 17:35:04.517600 diff --git a/src/ext_depends/D-YAML/test/data/timestamp.data b/src/ext_depends/D-YAML/test/data/timestamp.data new file mode 100644 index 0000000..7d214ce --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/timestamp.data @@ -0,0 +1,5 @@ +- 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 diff --git a/src/ext_depends/D-YAML/test/data/timestamp.detect b/src/ext_depends/D-YAML/test/data/timestamp.detect new file mode 100644 index 0000000..2013936 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/timestamp.detect @@ -0,0 +1 @@ +tag:yaml.org,2002:timestamp diff --git a/src/ext_depends/D-YAML/test/data/unclosed-bracket.loader-error b/src/ext_depends/D-YAML/test/data/unclosed-bracket.loader-error new file mode 100644 index 0000000..8c82077 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/unclosed-bracket.loader-error @@ -0,0 +1,6 @@ +test: + - [ foo: bar +# comment the rest of the stream to let the scanner detect the problem. +# - baz +#"we could have detected the unclosed bracket on the above line, but this would forbid such syntax as": { +#} diff --git a/src/ext_depends/D-YAML/test/data/unclosed-quoted-scalar.loader-error b/src/ext_depends/D-YAML/test/data/unclosed-quoted-scalar.loader-error new file mode 100644 index 0000000..8537429 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/unclosed-quoted-scalar.loader-error @@ -0,0 +1,2 @@ +'foo + bar diff --git a/src/ext_depends/D-YAML/test/data/undefined-anchor.loader-error b/src/ext_depends/D-YAML/test/data/undefined-anchor.loader-error new file mode 100644 index 0000000..9469103 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/undefined-anchor.loader-error @@ -0,0 +1,3 @@ +- foo +- &bar baz +- *bat diff --git a/src/ext_depends/D-YAML/test/data/undefined-tag-handle.loader-error b/src/ext_depends/D-YAML/test/data/undefined-tag-handle.loader-error new file mode 100644 index 0000000..82ba335 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/undefined-tag-handle.loader-error @@ -0,0 +1 @@ +--- !foo!bar baz diff --git a/src/ext_depends/D-YAML/test/data/unsupported-version.emitter-error b/src/ext_depends/D-YAML/test/data/unsupported-version.emitter-error new file mode 100644 index 0000000..f9c6197 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/unsupported-version.emitter-error @@ -0,0 +1,5 @@ +- !StreamStart +- !DocumentStart { version: [5,6] } +- !Scalar { value: foo } +- !DocumentEnd +- !StreamEnd diff --git a/src/ext_depends/D-YAML/test/data/uri.data b/src/ext_depends/D-YAML/test/data/uri.data new file mode 100644 index 0000000..4532bd8 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/uri.data @@ -0,0 +1,3 @@ +%TAG !e! tag:example.com,2000:app/ +--- +- !e!tag%F0%9F%A4%94 baz diff --git a/src/ext_depends/D-YAML/test/data/uri.detect b/src/ext_depends/D-YAML/test/data/uri.detect new file mode 100644 index 0000000..981dd7f --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/uri.detect @@ -0,0 +1 @@ +tag:example.com,2000:app/tag🤔 diff --git a/src/ext_depends/D-YAML/test/data/utf16be.code b/src/ext_depends/D-YAML/test/data/utf16be.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/utf16be.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/utf16be.data b/src/ext_depends/D-YAML/test/data/utf16be.data Binary files differnew file mode 100644 index 0000000..50dcfae --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/utf16be.data diff --git a/src/ext_depends/D-YAML/test/data/utf16le.code b/src/ext_depends/D-YAML/test/data/utf16le.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/utf16le.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/utf16le.data b/src/ext_depends/D-YAML/test/data/utf16le.data Binary files differnew file mode 100644 index 0000000..76f5e73 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/utf16le.data diff --git a/src/ext_depends/D-YAML/test/data/utf8-implicit.code b/src/ext_depends/D-YAML/test/data/utf8-implicit.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/utf8-implicit.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/utf8-implicit.data b/src/ext_depends/D-YAML/test/data/utf8-implicit.data new file mode 100644 index 0000000..9d8081e --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/utf8-implicit.data @@ -0,0 +1 @@ +--- implicit UTF-8 diff --git a/src/ext_depends/D-YAML/test/data/utf8.code b/src/ext_depends/D-YAML/test/data/utf8.code new file mode 100644 index 0000000..97e0aca --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/utf8.code @@ -0,0 +1 @@ +#dummy used in constructor test diff --git a/src/ext_depends/D-YAML/test/data/utf8.data b/src/ext_depends/D-YAML/test/data/utf8.data new file mode 100644 index 0000000..686f48a --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/utf8.data @@ -0,0 +1 @@ +--- UTF-8 diff --git a/src/ext_depends/D-YAML/test/data/value.data b/src/ext_depends/D-YAML/test/data/value.data new file mode 100644 index 0000000..c5b7680 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/value.data @@ -0,0 +1 @@ +- = diff --git a/src/ext_depends/D-YAML/test/data/value.detect b/src/ext_depends/D-YAML/test/data/value.detect new file mode 100644 index 0000000..7c37d02 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/value.detect @@ -0,0 +1 @@ +tag:yaml.org,2002:value diff --git a/src/ext_depends/D-YAML/test/data/yaml.data b/src/ext_depends/D-YAML/test/data/yaml.data new file mode 100644 index 0000000..a4bb3f8 --- /dev/null +++ b/src/ext_depends/D-YAML/test/data/yaml.data @@ -0,0 +1,3 @@ +- !!yaml '!' +- !!yaml '&' +- !!yaml '*' diff --git a/src/ext_depends/D-YAML/testsuite/dub.json b/src/ext_depends/D-YAML/testsuite/dub.json new file mode 100644 index 0000000..fece639 --- /dev/null +++ b/src/ext_depends/D-YAML/testsuite/dub.json @@ -0,0 +1,8 @@ +{ + "name": "testsuite", + "targetType": "executable", + "dependencies": + { + "dyaml": "*" + } +} diff --git a/src/ext_depends/D-YAML/testsuite/source/app.d b/src/ext_depends/D-YAML/testsuite/source/app.d new file mode 100644 index 0000000..6c26b32 --- /dev/null +++ b/src/ext_depends/D-YAML/testsuite/source/app.d @@ -0,0 +1,323 @@ +module dyaml.testsuite; + +import dyaml; +import dyaml.event; + +import std.algorithm; +import std.conv; +import std.file; +import std.format; +import std.json; +import std.path; +import std.range; +import std.stdio; +import std.string; +import std.typecons; +import std.utf; + +auto dumpEventString(string str) @safe +{ + string[] output; + try + { + auto events = Loader.fromString(str).parse(); + foreach (event; events) + { + string line; + final switch (event.id) + { + case EventID.scalar: + line = "=VAL "; + if (event.anchor != "") + { + line ~= text("&", event.anchor, " "); + } + if (event.tag != "") + { + line ~= text("<", event.tag, "> "); + } + switch(event.scalarStyle) + { + case ScalarStyle.singleQuoted: + line ~= "'"; + break; + case ScalarStyle.doubleQuoted: + line ~= '"'; + break; + case ScalarStyle.literal: + line ~= "|"; + break; + case ScalarStyle.folded: + line ~= ">"; + break; + default: + line ~= ":"; + break; + } + if (event.value != "") + { + line ~= text(event.value.substitute("\n", "\\n", `\`, `\\`, "\r", "\\r", "\t", "\\t", "\b", "\\b")); + } + break; + case EventID.streamStart: + line = "+STR"; + break; + case EventID.documentStart: + line = "+DOC"; + if (event.explicitDocument) + { + line ~= text(" ---"); + } + break; + case EventID.mappingStart: + line = "+MAP"; + if (event.anchor != "") + { + line ~= text(" &", event.anchor); + } + if (event.tag != "") + { + line ~= text(" <", event.tag, ">"); + } + break; + case EventID.sequenceStart: + line = "+SEQ"; + if (event.anchor != "") + { + line ~= text(" &", event.anchor); + } + if (event.tag != "") + { + line ~= text(" <", event.tag, ">"); + } + break; + case EventID.streamEnd: + line = "-STR"; + break; + case EventID.documentEnd: + line = "-DOC"; + if (event.explicitDocument) + { + line ~= " ..."; + } + break; + case EventID.mappingEnd: + line = "-MAP"; + break; + case EventID.sequenceEnd: + line = "-SEQ"; + break; + case EventID.alias_: + line = text("=ALI *", event.anchor); + break; + case EventID.invalid: + assert(0, "Invalid EventID produced"); + } + output ~= line; + } + } + catch (Exception) {} //Exceptions should just stop adding output + return output.join("\n"); +} + +enum TestState +{ + success, + skipped, + failure +} + +struct TestResult +{ + string name; + TestState state; + string failMsg; + + const void toString(OutputRange)(ref OutputRange writer) + if (isOutputRange!(OutputRange, char)) + { + ubyte statusColour; + string statusString; + final switch (state) { + case TestState.success: + statusColour = 32; + statusString = "Succeeded"; + break; + case TestState.failure: + statusColour = 31; + statusString = "Failed"; + break; + case TestState.skipped: + statusColour = 93; + statusString = "Skipped"; + break; + } + writer.formattedWrite!"[\033[%s;1m%s\033[0m] %s"(statusColour, statusString, name); + if (state != TestState.success) + { + writer.formattedWrite!" (%s)"(failMsg.replace("\n", " ")); + } + } +} + +TestResult runTests(string tml) @safe +{ + TestResult output; + output.state = TestState.success; + auto splitFile = tml.splitter("\n--- "); + output.name = splitFile.front.findSplit("=== ")[2]; + bool loadFailed, shouldFail; + string failMsg; + JSONValue json; + Node[] nodes; + string yamlString; + Nullable!string compareYAMLString; + Nullable!string events; + ulong testsRun; + + void fail(string msg) @safe + { + output.state = TestState.failure; + output.failMsg = msg; + } + void skip(string msg) @safe + { + output.state = TestState.skipped; + output.failMsg = msg; + } + void parseYAML(string yaml) @safe + { + yamlString = yaml; + try { + nodes = Loader.fromString(yamlString).array; + } + catch (Exception e) + { + loadFailed = true; + failMsg = e.msg; + } + } + void compareLineByLine(const string a, const string b, const string msg) @safe + { + foreach (line1, line2; zip(a.lineSplitter, b.lineSplitter)) + { + if (line1 != line2) + { + fail(text(msg, " Got ", line1, ", expected ", line2)); + break; + } + } + } + foreach (section; splitFile.drop(1)) + { + auto splitSection = section.findSplit("\n"); + auto splitSectionHeader = splitSection[0].findSplit(":"); + const splitSectionName = splitSectionHeader[0].findSplit("("); + const sectionName = splitSectionName[0]; + const sectionParams = splitSectionName[2].findSplit(")")[0]; + string sectionData = splitSection[2]; + if (sectionData != "") + { + //< means dedent. + if (sectionParams.canFind("<")) + { + sectionData = sectionData[4..$].substitute("\n ", "\n", "<SPC>", " ", "<TAB>", "\t").toUTF8; + } + else + { + sectionData = sectionData.substitute("<SPC>", " ", "<TAB>", "\t").toUTF8; + } + //Not sure what + means. + } + switch(sectionName) + { + case "in-yaml": + parseYAML(sectionData); + break; + case "in-json": + json = parseJSON(sectionData); + break; + case "test-event": + events = sectionData; + break; + case "error": + shouldFail = true; + testsRun++; + break; + case "out-yaml": + compareYAMLString = sectionData; + break; + case "emit-yaml": + // TODO: Figure out how/if to implement this + //fail("Unhandled test - emit-yaml"); + break; + case "lex-token": + // TODO: Should this be implemented? + //fail("Unhandled test - lex-token"); + break; + case "from": break; + case "tags": break; + default: assert(false, text("Unhandled section ", sectionName, "in ", output.name)); + } + } + if (!loadFailed && !compareYAMLString.isNull && !shouldFail) + { + Appender!string buf; + dumper().dump(buf); + compareLineByLine(buf.data, compareYAMLString.get, "Dumped YAML mismatch"); + testsRun++; + } + if (!loadFailed && !events.isNull && !shouldFail) + { + const compare = dumpEventString(yamlString); + compareLineByLine(compare, events.get, "Event mismatch"); + testsRun++; + } + if (loadFailed && !shouldFail) + { + fail(failMsg); + } + if (shouldFail && !loadFailed) + { + fail("Invalid YAML accepted"); + } + if ((testsRun == 0) && (output.state != TestState.failure)) + { + skip("No tests run"); + } + return output; +} + +// Can't be @safe due to dirEntries() +void main(string[] args) @system +{ + string path = "yaml-test-suite/test"; + + void printResult(string id, TestResult result) + { + writeln(id, " ", result); + } + + if (args.length > 1) + { + path = args[1]; + } + + ulong total; + ulong successes; + foreach (file; dirEntries(path, "*.tml", SpanMode.shallow)) + { + auto result = runTests(readText(file)); + if (result.state == TestState.success) + { + debug(verbose) printResult(file.baseName, result); + successes++; + } + else + { + printResult(file.baseName, result); + } + total++; + } + writefln!"%d/%d tests passed"(successes, total); +} |