Initial commit.
31
.gitignore
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Backups #
|
||||
###########
|
||||
*~
|
||||
*.sw*
|
||||
|
||||
# Compiled source #
|
||||
###################
|
||||
unittest
|
||||
cdc
|
||||
main
|
||||
*.a
|
||||
*.lib
|
||||
*.o
|
||||
*.exe
|
||||
|
||||
# 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
|
23
LICENSE_1_0.txt
Normal file
|
@ -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.
|
450
README.html
Normal file
|
@ -0,0 +1,450 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="generator" content="Docutils 0.7: http://docutils.sourceforge.net/" />
|
||||
<title>D:YAML 0.1</title>
|
||||
<style type="text/css">
|
||||
|
||||
/*
|
||||
:Author: David Goodger (goodger@python.org)
|
||||
:Id: $Id: html4css1.css 6253 2010-03-02 00:24:53Z milde $
|
||||
:Copyright: This stylesheet has been placed in the public domain.
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
|
||||
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
|
||||
customize this style sheet.
|
||||
*/
|
||||
|
||||
/* used to remove borders from tables and images */
|
||||
.borderless, table.borderless td, table.borderless th {
|
||||
border: 0 }
|
||||
|
||||
table.borderless td, table.borderless th {
|
||||
/* Override padding for "table.docutils td" with "! important".
|
||||
The right padding separates the table cells. */
|
||||
padding: 0 0.5em 0 0 ! important }
|
||||
|
||||
.first {
|
||||
/* Override more specific margin styles with "! important". */
|
||||
margin-top: 0 ! important }
|
||||
|
||||
.last, .with-subtitle {
|
||||
margin-bottom: 0 ! important }
|
||||
|
||||
.hidden {
|
||||
display: none }
|
||||
|
||||
a.toc-backref {
|
||||
text-decoration: none ;
|
||||
color: black }
|
||||
|
||||
blockquote.epigraph {
|
||||
margin: 2em 5em ; }
|
||||
|
||||
dl.docutils dd {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
/* Uncomment (and remove this text!) to get bold-faced definition list terms
|
||||
dl.docutils dt {
|
||||
font-weight: bold }
|
||||
*/
|
||||
|
||||
div.abstract {
|
||||
margin: 2em 5em }
|
||||
|
||||
div.abstract p.topic-title {
|
||||
font-weight: bold ;
|
||||
text-align: center }
|
||||
|
||||
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||
div.hint, div.important, div.note, div.tip, div.warning {
|
||||
margin: 2em ;
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||
div.important p.admonition-title, div.note p.admonition-title,
|
||||
div.tip p.admonition-title {
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||
div.danger p.admonition-title, div.error p.admonition-title,
|
||||
div.warning p.admonition-title {
|
||||
color: red ;
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||
compound paragraphs.
|
||||
div.compound .compound-first, div.compound .compound-middle {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
div.compound .compound-last, div.compound .compound-middle {
|
||||
margin-top: 0.5em }
|
||||
*/
|
||||
|
||||
div.dedication {
|
||||
margin: 2em 5em ;
|
||||
text-align: center ;
|
||||
font-style: italic }
|
||||
|
||||
div.dedication p.topic-title {
|
||||
font-weight: bold ;
|
||||
font-style: normal }
|
||||
|
||||
div.figure {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
div.footer, div.header {
|
||||
clear: both;
|
||||
font-size: smaller }
|
||||
|
||||
div.line-block {
|
||||
display: block ;
|
||||
margin-top: 1em ;
|
||||
margin-bottom: 1em }
|
||||
|
||||
div.line-block div.line-block {
|
||||
margin-top: 0 ;
|
||||
margin-bottom: 0 ;
|
||||
margin-left: 1.5em }
|
||||
|
||||
div.sidebar {
|
||||
margin: 0 0 0.5em 1em ;
|
||||
border: medium outset ;
|
||||
padding: 1em ;
|
||||
background-color: #ffffee ;
|
||||
width: 40% ;
|
||||
float: right ;
|
||||
clear: right }
|
||||
|
||||
div.sidebar p.rubric {
|
||||
font-family: sans-serif ;
|
||||
font-size: medium }
|
||||
|
||||
div.system-messages {
|
||||
margin: 5em }
|
||||
|
||||
div.system-messages h1 {
|
||||
color: red }
|
||||
|
||||
div.system-message {
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.system-message p.system-message-title {
|
||||
color: red ;
|
||||
font-weight: bold }
|
||||
|
||||
div.topic {
|
||||
margin: 2em }
|
||||
|
||||
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||
margin-top: 0.4em }
|
||||
|
||||
h1.title {
|
||||
text-align: center }
|
||||
|
||||
h2.subtitle {
|
||||
text-align: center }
|
||||
|
||||
hr.docutils {
|
||||
width: 75% }
|
||||
|
||||
img.align-left, .figure.align-left, object.align-left {
|
||||
clear: left ;
|
||||
float: left ;
|
||||
margin-right: 1em }
|
||||
|
||||
img.align-right, .figure.align-right, object.align-right {
|
||||
clear: right ;
|
||||
float: right ;
|
||||
margin-left: 1em }
|
||||
|
||||
img.align-center, .figure.align-center, object.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left }
|
||||
|
||||
.align-center {
|
||||
clear: both ;
|
||||
text-align: center }
|
||||
|
||||
.align-right {
|
||||
text-align: right }
|
||||
|
||||
/* reset inner alignment in figures */
|
||||
div.align-right {
|
||||
text-align: left }
|
||||
|
||||
/* div.align-center * { */
|
||||
/* text-align: left } */
|
||||
|
||||
ol.simple, ul.simple {
|
||||
margin-bottom: 1em }
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal }
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha }
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha }
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman }
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman }
|
||||
|
||||
p.attribution {
|
||||
text-align: right ;
|
||||
margin-left: 50% }
|
||||
|
||||
p.caption {
|
||||
font-style: italic }
|
||||
|
||||
p.credits {
|
||||
font-style: italic ;
|
||||
font-size: smaller }
|
||||
|
||||
p.label {
|
||||
white-space: nowrap }
|
||||
|
||||
p.rubric {
|
||||
font-weight: bold ;
|
||||
font-size: larger ;
|
||||
color: maroon ;
|
||||
text-align: center }
|
||||
|
||||
p.sidebar-title {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold ;
|
||||
font-size: larger }
|
||||
|
||||
p.sidebar-subtitle {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
p.topic-title {
|
||||
font-weight: bold }
|
||||
|
||||
pre.address {
|
||||
margin-bottom: 0 ;
|
||||
margin-top: 0 ;
|
||||
font: inherit }
|
||||
|
||||
pre.literal-block, pre.doctest-block {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
span.classifier {
|
||||
font-family: sans-serif ;
|
||||
font-style: oblique }
|
||||
|
||||
span.classifier-delimiter {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
span.interpreted {
|
||||
font-family: sans-serif }
|
||||
|
||||
span.option {
|
||||
white-space: nowrap }
|
||||
|
||||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic {
|
||||
color: red }
|
||||
|
||||
span.section-subtitle {
|
||||
/* font-size relative to parent (h1..h6 element) */
|
||||
font-size: 80% }
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docinfo {
|
||||
margin: 2em 4em }
|
||||
|
||||
table.docutils {
|
||||
margin-top: 0.5em ;
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
table.footnote {
|
||||
border-left: solid 1px black;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docutils td, table.docutils th,
|
||||
table.docinfo td, table.docinfo th {
|
||||
padding-left: 0.5em ;
|
||||
padding-right: 0.5em ;
|
||||
vertical-align: top }
|
||||
|
||||
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||
font-weight: bold ;
|
||||
text-align: left ;
|
||||
white-space: nowrap ;
|
||||
padding-left: 0 }
|
||||
|
||||
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||
font-size: 100% }
|
||||
|
||||
ul.auto-toc {
|
||||
list-style-type: none }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document" id="d-yaml-0-1">
|
||||
<h1 class="title">D:YAML 0.1</h1>
|
||||
|
||||
<div class="section" id="introduction">
|
||||
<h1>Introduction</h1>
|
||||
<p>D:YAML is an open source YAML parser library for the D programming language.
|
||||
It is (<a class="reference external" href="./doc/html/articles/spec_differences.html">almost</a>) compliant to the
|
||||
YAML 1.1 specification. Much of D:YAML code is based on
|
||||
<a class="reference external" href="http://www.pyyaml.org">PyYAML</a> created by Kirill Simonov. D:YAML has no
|
||||
external dependencies, all it needs is a D compiler and Phobos (standard
|
||||
library). It is written in D2 and there are no plans for D1 or Tango support.</p>
|
||||
<p>At the moment, D:YAML can only read, not write YAML files. This will change in
|
||||
the following releases. D:YAML is designed to be as easy to use as possible while
|
||||
supporting the full feature set of YAML. To start using it in your project,
|
||||
you can see the <a class="reference external" href="./doc/html/tutorials/getting_started.html">Getting Started</a>
|
||||
tutorial.</p>
|
||||
<p>D:YAML is still a work in progress. Its API is still not stable and there might
|
||||
be compatibility breaking changes. For instance, currently some D:YAML API
|
||||
functions depend on the <tt class="docutils literal">std.stream</tt> module in Phobos. This module is expected
|
||||
to be rewritten in future and D:YAML will change accordingly.</p>
|
||||
</div>
|
||||
<div class="section" id="features">
|
||||
<h1>Features</h1>
|
||||
<ul class="simple">
|
||||
<li>Easy to use, high-level API and detailed debugging messages.</li>
|
||||
<li>Detailed API documentation and tutorials.</li>
|
||||
<li>No external dependencies.</li>
|
||||
<li>Supports all YAML 1.1 constructs. All examples from the YAML 1.1 specification
|
||||
are parsed correctly.</li>
|
||||
<li>Read from YAML files as well as from memory or user defined streams.</li>
|
||||
<li>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).</li>
|
||||
<li>Support for both block (Python-like, based on indentation) and flow
|
||||
(JSON-like, based on bracing) constructs.</li>
|
||||
<li>Support for YAML anchors and aliases.</li>
|
||||
<li>Support for default values in mappings.</li>
|
||||
<li>Support for custom tags (data types), and implicit tag resolution for custom
|
||||
tags.</li>
|
||||
<li>All tags (data types) described at <a class="reference external" href="http://yaml.org/type/">http://yaml.org/type/</a> are supported, with
|
||||
the exception of <tt class="docutils literal">tag:yaml.org,2002:yaml</tt>, which is used to represent YAML
|
||||
code in YAML.</li>
|
||||
<li>Cannot write YAML at the moment. This will change in the future.</li>
|
||||
<li>There is no support for recursive data structures (supported by some YAML
|
||||
parsers). There are no plans to implement this at the moment.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="directory-structure">
|
||||
<h1>Directory structure</h1>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="17%" />
|
||||
<col width="83%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">Directory</th>
|
||||
<th class="head">Contents</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td><tt class="docutils literal">./</tt></td>
|
||||
<td>This README file, utility scripts, D:YAML sources outside any packages.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">./doc</tt></td>
|
||||
<td>Documentation.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">./docsrc</tt></td>
|
||||
<td>Documentation sources.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">./dyaml</tt></td>
|
||||
<td>D:YAML source code.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">./examples/</tt></td>
|
||||
<td>Example D:YAML code.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">./test</tt></td>
|
||||
<td>Unittest code and inputs.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="section" id="installing-and-tutorial">
|
||||
<h1>Installing and tutorial</h1>
|
||||
<p>See the <a class="reference external" href="./doc/html/tutorials/getting_started.html">Getting started</a> tutorial
|
||||
and other tutorials that can be found in the <tt class="docutils literal">doc/html/tutorials/</tt> directory.</p>
|
||||
</div>
|
||||
<div class="section" id="license">
|
||||
<h1>License</h1>
|
||||
<p>D:YAML is released under the terms of the
|
||||
<a class="reference external" href="http://www.boost.org/LICENSE_1_0.txt">Boost Software License 1.0</a>.
|
||||
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.</p>
|
||||
<p>Full text of the license can be found in file <tt class="docutils literal">LICENSE_1_0.txt</tt> and is also
|
||||
displayed here:</p>
|
||||
<pre class="literal-block">
|
||||
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.
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="credits">
|
||||
<h1>Credits</h1>
|
||||
<p>D:YAML was created by Ferdinand Majerech aka Kiith-Sa kiithsacmp[AT]gmail.com .</p>
|
||||
<p>Parts of code based on <a class="reference external" href="http://www.pyyaml.org">PyYAML</a> created by Kirill Simonov.</p>
|
||||
<p>D:YAML uses a modified version of the
|
||||
<a class="reference external" href="http://www.dsource.org/projects/cdc">CDC build script</a>.</p>
|
||||
<p>D:YAML was created using Vim and DMD on Debian and Ubuntu Linux as a YAML parsing
|
||||
library for the <a class="reference external" href="http://www.d-programming-language.org">D programming language</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<hr class="footer" />
|
||||
Generated on: 2011-08-15 00:44 UTC.
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
129
README.rst
Normal file
|
@ -0,0 +1,129 @@
|
|||
==========
|
||||
D:YAML 0.1
|
||||
==========
|
||||
|
||||
------------
|
||||
Introduction
|
||||
------------
|
||||
|
||||
D:YAML is an open source YAML parser library for the D programming language.
|
||||
It is (`almost <./doc/html/articles/spec_differences.html>`_) compliant to the
|
||||
YAML 1.1 specification. Much of D:YAML code is based on
|
||||
`PyYAML <http://www.pyyaml.org>`_ created by Kirill Simonov. D:YAML has no
|
||||
external dependencies, all it needs is a D compiler and Phobos (standard
|
||||
library). It is written in D2 and there are no plans for D1 or Tango support.
|
||||
|
||||
At the moment, D:YAML can only read, not write YAML files. This will change in
|
||||
the following releases. D:YAML is designed to be as easy to use as possible while
|
||||
supporting the full feature set of YAML. To start using it in your project,
|
||||
you can see the `Getting Started <./doc/html/tutorials/getting_started.html>`_
|
||||
tutorial.
|
||||
|
||||
D:YAML is still a work in progress. Its API is still not stable and there might
|
||||
be compatibility breaking changes. For instance, currently some D:YAML API
|
||||
functions depend on the ``std.stream`` module in Phobos. This module is expected
|
||||
to be rewritten in future and D:YAML will change accordingly.
|
||||
|
||||
|
||||
--------
|
||||
Features
|
||||
--------
|
||||
|
||||
* Easy to use, high-level API and detailed debugging messages.
|
||||
* Detailed API documentation and tutorials.
|
||||
* No external dependencies.
|
||||
* Supports all YAML 1.1 constructs. All examples from the YAML 1.1 specification
|
||||
are parsed correctly.
|
||||
* Read from YAML files as well as from memory or user defined streams.
|
||||
* 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
|
||||
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.
|
||||
* Cannot write YAML at the moment. This will change in the future.
|
||||
* There is no support for recursive data structures.
|
||||
There are no plans to implement this at the moment.
|
||||
|
||||
|
||||
-------------------
|
||||
Directory structure
|
||||
-------------------
|
||||
|
||||
=============== ======================================================================
|
||||
Directory Contents
|
||||
=============== ======================================================================
|
||||
``./`` This README file, utility scripts, D:YAML sources outside any packages.
|
||||
``./doc`` Documentation.
|
||||
``./docsrc`` Documentation sources.
|
||||
``./dyaml`` D:YAML source code.
|
||||
``./examples/`` Example D:YAML code.
|
||||
``./test`` Unittest code and inputs.
|
||||
=============== ======================================================================
|
||||
|
||||
|
||||
-----------------------
|
||||
Installing and tutorial
|
||||
-----------------------
|
||||
|
||||
See the `Getting started <./doc/html/tutorials/getting_started.html>`_ tutorial
|
||||
and other tutorials that can be found in the ``doc/html/tutorials/`` directory.
|
||||
|
||||
|
||||
-------
|
||||
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 kiithsacmp[AT]gmail.com .
|
||||
|
||||
Parts of code based on `PyYAML <http://www.pyyaml.org>`_ created by Kirill Simonov.
|
||||
|
||||
D:YAML uses a modified version of the
|
||||
`CDC build script <http://www.dsource.org/projects/cdc>`_.
|
||||
|
||||
D:YAML was created using Vim and DMD on Debian and Ubuntu Linux as a YAML parsing
|
||||
library for the `D programming language <http://www.d-programming-language.org>`_.
|
37
autoddoc.cfg
Normal file
|
@ -0,0 +1,37 @@
|
|||
[PROJECT]
|
||||
# Name of the project. E.g. "AutoDDoc Documentation Generator".
|
||||
name = D:YAML
|
||||
# Project version string. E.g. "0.1 alpha".
|
||||
version = 0.1
|
||||
# Copyright without the "Copyright (c)" part. E.g. "Joe Coder 2001-2042".
|
||||
copyright = Ferdinand Majerech 2011. Based on <a href="http://www.pyyaml.org">PyYAML</a> by Kirill Simonov.
|
||||
# File name of the logo of the project, if any.
|
||||
# Should be a PNG image. E.g. "logo.png".
|
||||
logo = docsrc/logo128.png
|
||||
|
||||
[OUTPUT]
|
||||
# Directory to write the documentation to.
|
||||
# If none specified, "autoddoc" is used.
|
||||
directory = doc/html/api
|
||||
# CSS style to use. If empty, default will be generated.
|
||||
# You can create a custom style by generating default style
|
||||
# with "autoddoc.py -s" and modyfing it.
|
||||
style =
|
||||
# Documentation index file to use. If empty, default will be generated.
|
||||
# You can create a custom index by generating default index
|
||||
# with "autoddoc.py -i" and modyfing it.
|
||||
index = docsrc/autoddoc_index.dd
|
||||
# Any extra links to add to the sidebar of the documentation.
|
||||
# Should be in the format "LINK DESCRIPTION", separated by commas.
|
||||
# E.g; To add links to Google and the D language site, you would use:
|
||||
# "http://www.google.com Google, http://d-p-l.org DLang"
|
||||
links = ../index.html Documentation home
|
||||
# Source files or patterns to ignore. Supports regexp syntax.
|
||||
# E.g; To ignore main.d and all source files in the test/ directory,
|
||||
# you would use: "main.d test/*"
|
||||
ignore = test/*, examples/*, docsrc/*, autoddoc/*, yaml.d, unittest.d, cdc.d, dyaml/composer.d, dyaml/event.d, dyaml/parser.d, dyaml/reader.d, dyaml/scanner.d, dyaml/token.d, dyaml/util.d
|
||||
|
||||
[DDOC]
|
||||
# Command to use to generate the documentation.
|
||||
# Can be modified e.g. to use GDC or LDC.
|
||||
ddoc_command = dmd -d -c -o-
|
657
autoddoc.py
Executable file
|
@ -0,0 +1,657 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
# License: Boost 1.0
|
||||
#
|
||||
# Copyright (c) 2011 Ferdinand Majerech
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
import argparse
|
||||
import configparser
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
|
||||
template_macros =\
|
||||
("PBR = <div class=\"pbr\">$0</div>\n"
|
||||
"BR = <br>\n"
|
||||
"DDOC_DITTO = $(BR)$0\n"
|
||||
"DDOC_SUMMARY = $(P $0)\n"
|
||||
"DDOC_DESCRIPTION = $(P $0)\n"
|
||||
"DDOC_AUTHORS = $(B Authors:)$(PBR $0)\n"
|
||||
"DDOC_BUGS = $(RED BUGS:)$(PBR $0)\n"
|
||||
"DDOC_COPYRIGHT = $(B Copyright:)$(PBR $0)\n"
|
||||
"DDOC_DATE = $(B Date:)$(PBR $0)\n"
|
||||
"DDOC_DEPRECATED = $(RED Deprecated:)$(PBR $0)\n"
|
||||
"DDOC_EXAMPLES = $(B Examples:)$(PBR $0)\n"
|
||||
"DDOC_HISTORY = $(B History:)$(PBR $0)\n"
|
||||
"DDOC_LICENSE = $(B License:)$(PBR $0)\n"
|
||||
"DDOC_RETURNS = $(B Returns:)$(PBR $0)\n"
|
||||
"DDOC_SEE_ALSO = $(B See Also:)$(PBR $0)\n"
|
||||
"DDOC_STANDARDS = $(B Standards:)$(PBR $0)\n"
|
||||
"DDOC_THROWS = $(B Throws:)$(PBR $0)\n"
|
||||
"DDOC_VERSION = $(B Version:)$(PBR $0)\n"
|
||||
"DDOC_SECTION_H = $(B $0)$(BR)\n"
|
||||
"DDOC_SECTION = $(P $0)\n"
|
||||
"DDOC_PARAMS = $(B Parameters:)$(PBR <table class=parms>$0</table>)\n"
|
||||
"DDOC_PARAM = $(B $0)\n"
|
||||
"DDOC_BLANKLINE = $(BR)\n"
|
||||
|
||||
"RED = <span style=\"color:red\">$0</span>\n"
|
||||
"GREEN = <span style=\"color:green\">$0</span>\n"
|
||||
"BLUE = <span style=\"color:blue\">$0</span>\n"
|
||||
"YELLOW = <span style=\"color:yellow\">$0</span>\n"
|
||||
"BLACK = <span style=\"color:black\">$0</span>\n"
|
||||
"WHITE = <span style=\"color:white\">$0</span>\n"
|
||||
|
||||
"D_COMMENT = <span class=\"d_comment\">$0</span>\n"
|
||||
"D_STRING = <span class=\"d_string\">$0</span>\n"
|
||||
"D_KEYWORD = <span class=\"d_keyword\">$0</span>\n"
|
||||
"D_PSYMBOL = <span class=\"d_psymbol\">$0</span>\n"
|
||||
"D_PARAM = <span class=\"d_param\">$0</span>\n"
|
||||
|
||||
"RPAREN = )\n"
|
||||
"LPAREN = (\n"
|
||||
"LESS = <\n"
|
||||
"GREATER = >\n"
|
||||
"D = <font face=Courier><b>$0</b></font>\n"
|
||||
"D = <span class=\"d_inlinecode\">$0</span>\n"
|
||||
|
||||
"DDOC_PSYMBOL = <a name=\"$0\"></a><span class=\"ddoc_psymbol\">$0</span>\n"
|
||||
"DDOC_DECL = <dt class=\"d_decl\">$0</dt>\n"
|
||||
"LREF = <a href=\"#$1\">$(D $1)</a>\n"
|
||||
"XREF = <a href=\"$1.html#$2\"$(D $1.$2)\n"
|
||||
"PRE = <pre>$0</pre>\n"
|
||||
|
||||
"TABLE = <table cellspacing=0 cellpadding=5><caption>$1</caption>$2</table>\n"
|
||||
"TD = <td valign=top>$0</td>\n"
|
||||
"SUB = <sub>$0</sub>\n")
|
||||
|
||||
template_header =\
|
||||
("\n<html lang='en'>\n"
|
||||
"<head>\n"
|
||||
"<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" >\n"
|
||||
"<title>$(TITLE) - $(PROJECT_NAME) $(PROJECT_VERSION) API documentation</title>\n"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"css/style.css\">\n"
|
||||
"</head>\n\n")
|
||||
|
||||
template_footer =\
|
||||
("\n<div id=\"copyright\">\n"
|
||||
"$(COPYRIGHT) |\n"
|
||||
"Page generated by Autodoc and $(LINK2 http://www.digitalmars.com/d/2.0/ddoc.html, Ddoc).\n"
|
||||
"</div>\n\n")
|
||||
|
||||
default_css =\
|
||||
("body\n"
|
||||
"{\n"
|
||||
" margin: 0;\n"
|
||||
" padding: 0;\n"
|
||||
" border: 0;\n"
|
||||
" color: black;\n"
|
||||
" background-color: #1f252b;\n"
|
||||
" font-size: 100%;\n"
|
||||
" font-family: Verdana, \"Deja Vu\", \"Bitstream Vera Sans\", sans-serif;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"h1, h2, h3, h4, h5, h6\n"
|
||||
"{\n"
|
||||
" font-family: Georgia, \"Times New Roman\", Times, serif;\n"
|
||||
" font-weight: normal;\n"
|
||||
" color: #633;\n"
|
||||
" line-height: normal;\n"
|
||||
" text-align: left;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"h1\n"
|
||||
"{\n"
|
||||
" margin-top: 0;\n"
|
||||
" font-size: 2.5em;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"h2{font-size: 1.7em;}\n"
|
||||
"\n"
|
||||
"h3{font-size: 1.35em;}\n"
|
||||
"\n"
|
||||
"h4\n"
|
||||
"{\n"
|
||||
" font-size: 1.15em;\n"
|
||||
" font-style: italic;\n"
|
||||
" margin-bottom: 0;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"pre\n"
|
||||
"{\n"
|
||||
" background: #eef;\n"
|
||||
" padding: 1ex;\n"
|
||||
" margin: 1em 0 1em 3em;\n"
|
||||
" font-family: monospace;\n"
|
||||
" font-size: 1.2em;\n"
|
||||
" line-height: normal;\n"
|
||||
" border: 1px solid #ccc;\n"
|
||||
" width: auto;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"dd\n"
|
||||
"{\n"
|
||||
" padding: 1ex;\n"
|
||||
" margin-left: 3em;\n"
|
||||
" margin-bottom: 1em;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"td{text-align: justify;}\n"
|
||||
"\n"
|
||||
"hr{margin: 2em 0;}\n"
|
||||
"\n"
|
||||
"a{color: #006;}\n"
|
||||
"\n"
|
||||
"a:visited{color: #606;}\n"
|
||||
"\n"
|
||||
"/* These are different kinds of <pre> sections */\n"
|
||||
".console /* command line console */\n"
|
||||
"{\n"
|
||||
" background-color: #f7f7f7;\n"
|
||||
" color: #181818;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
".moddeffile /* module definition file */\n"
|
||||
"{\n"
|
||||
" background-color: #efeffe;\n"
|
||||
" color: #010199;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
".d_code /* D code */\n"
|
||||
"{\n"
|
||||
" background-color: #fcfcfc;\n"
|
||||
" color: #000066;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
".d_code2 /* D code */\n"
|
||||
"{\n"
|
||||
" background-color: #fcfcfc;\n"
|
||||
" color: #000066;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"td .d_code2\n"
|
||||
"{\n"
|
||||
" min-width: 20em;\n"
|
||||
" margin: 1em 0em;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
".d_inlinecode\n"
|
||||
"{\n"
|
||||
" font-family: monospace;\n"
|
||||
" font-weight: bold;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"/* Elements of D source code text */\n"
|
||||
".d_comment{color: green;}\n"
|
||||
".d_string {color: red;}\n"
|
||||
".d_keyword{color: blue;}\n"
|
||||
".d_psymbol{text-decoration: underline;}\n"
|
||||
".d_param {font-style: italic;}\n"
|
||||
"\n"
|
||||
"/* Focal symbol that is being documented */\n"
|
||||
".ddoc_psymbol{color: #336600;}\n"
|
||||
"\n"
|
||||
"div#top{max-width: 85em;}\n"
|
||||
"\n"
|
||||
"div#header{padding: 0.2em 1em 0.2em 1em;}\n"
|
||||
"div.pbr\n"
|
||||
"{\n"
|
||||
" margin: 4px 0px 8px 10px"
|
||||
"}\n"
|
||||
"\n"
|
||||
"img#logo{vertical-align: bottom;}\n"
|
||||
"\n"
|
||||
"#main-heading\n"
|
||||
"{\n"
|
||||
" margin-left: 1em;\n"
|
||||
" color: white;\n"
|
||||
" font-size: 1.4em;\n"
|
||||
" font-family: Arial, Verdana, sans-serif;\n"
|
||||
" font-variant: small-caps;\n"
|
||||
" text-decoration: none;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"div#navigation\n"
|
||||
"{\n"
|
||||
" font-size: 0.875em;\n"
|
||||
" float: left;\n"
|
||||
" width: 12.0em;\n"
|
||||
" padding: 0 1.5em;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"div.navblock\n"
|
||||
"{\n"
|
||||
" margin-top: 0;\n"
|
||||
" margin-bottom: 1em;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"div#navigation .navblock h2\n"
|
||||
"{\n"
|
||||
" font-family: Verdana, \"Deja Vu\", \"Bitstream Vera Sans\", sans-serif;\n"
|
||||
" font-size: 1.35em;\n"
|
||||
" color: #ccc;\n"
|
||||
" margin: 0;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"div#navigation .navblock ul\n"
|
||||
"{\n"
|
||||
" list-style-type: none;\n"
|
||||
" margin: 0;\n"
|
||||
" padding: 0;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"div#navigation .navblock li\n"
|
||||
"{\n"
|
||||
" margin: 0 0 0 0.8em;\n"
|
||||
" padding: 0;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"#navigation .navblock a\n"
|
||||
"{\n"
|
||||
" display: block;\n"
|
||||
" color: #ddd;\n"
|
||||
" text-decoration: none;\n"
|
||||
" padding: 0.1em 0;\n"
|
||||
" border-bottom: 1px dashed #444;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"#navigation .navblock a:hover{color: white;}\n"
|
||||
"\n"
|
||||
"#navigation .navblock a.active\n"
|
||||
"{\n"
|
||||
" color: white;\n"
|
||||
" border-color: white;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"div#content\n"
|
||||
"{\n"
|
||||
" min-height: 440px;\n"
|
||||
" margin-left: 15em;\n"
|
||||
" margin-right: 1.6em;\n"
|
||||
" padding: 1.6em;\n"
|
||||
" padding-top: 1.3em;\n"
|
||||
" border: 0.6em solid #cccccc;\n"
|
||||
" background-color: #f6f6f6;\n"
|
||||
" font-size: 0.875em;\n"
|
||||
" line-height: 1.4em;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"div#content li{padding-bottom: .7ex;}\n"
|
||||
"\n"
|
||||
"div#copyright\n"
|
||||
"{\n"
|
||||
" padding: 1em 2em;\n"
|
||||
" background-color: #303333;\n"
|
||||
" color: #ccc;\n"
|
||||
" font-size: 0.75em;\n"
|
||||
" text-align: center;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"div#copyright a{color: #ccc;}\n"
|
||||
"\n"
|
||||
".d_inlinecode\n"
|
||||
"{\n"
|
||||
" font-family: Consolas, \"Bitstream Vera Sans Mono\", \"Andale Mono\", \"DejaVu Sans Mono\", \"Lucida Console\", monospace;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
".d_decl\n"
|
||||
"{\n"
|
||||
" font-weight: bold;\n"
|
||||
" background-color: #E4E9EF;\n"
|
||||
" border-bottom: solid 2px #336600;\n"
|
||||
" padding: 2px 0px 2px 2px;\n"
|
||||
"}\n")
|
||||
|
||||
default_cfg =\
|
||||
("[PROJECT]\n"
|
||||
"# Name of the project. E.g. \"AutoDDoc Documentation Generator\".\n"
|
||||
"name =\n"
|
||||
"# Project version string. E.g. \"0.1 alpha\".\n"
|
||||
"version =\n"
|
||||
"# Copyright without the \"Copyright (c)\" part. E.g. \"Joe Coder 2001-2042\".\n"
|
||||
"copyright =\n"
|
||||
"# File name of the logo of the project, if any. \n"
|
||||
"# Should be a PNG image. E.g. \"logo.png\".\n"
|
||||
"logo =\n"
|
||||
"\n"
|
||||
"[OUTPUT]\n"
|
||||
"# Directory to write the documentation to.\n"
|
||||
"# If none specified, \"autoddoc\" is used.\n"
|
||||
"directory = autoddoc\n"
|
||||
"# CSS style to use. If empty, default will be generated.\n"
|
||||
"# You can create a custom style by generating default style\n"
|
||||
"# with \"autoddoc.py -s\" and modyfing it.\n"
|
||||
"style =\n"
|
||||
"# Documentation index file to use. If empty, default will be generated.\n"
|
||||
"# You can create a custom index by generating default index\n"
|
||||
"# with \"autoddoc.py -i\" and modyfing it.\n"
|
||||
"index =\n"
|
||||
"# Any extra links to add to the sidebar of the documentation.\n"
|
||||
"# Should be in the format \"LINK DESCRIPTION\", separated by commas.\n"
|
||||
"# E.g; To add links to Google and the D language site, you would use:\n"
|
||||
"# \"http://www.google.com Google, http://d-p-l.org DLang\"\n"
|
||||
"links =\n"
|
||||
"# Source files or patterns to ignore. Supports regexp syntax.\n"
|
||||
"# E.g; To ignore main.d and all source files in the test/ directory,\n"
|
||||
"# you would use: \"main.d, test/*\"\n"
|
||||
"ignore =\n"
|
||||
"\n"
|
||||
"[DDOC]\n"
|
||||
"# Command to use to generate the documentation. \n"
|
||||
"# Can be modified e.g. to use GDC or LDC.\n"
|
||||
"ddoc_command = dmd -d -c -o-\n")
|
||||
|
||||
class ProjectInfo:
|
||||
"""Holds project-specific data"""
|
||||
def __init__(self, name, version, copyright, logo_file):
|
||||
self.name = name
|
||||
self.version = version
|
||||
self.copyright = copyright
|
||||
self.logo_file = logo_file
|
||||
|
||||
def run_cmd(cmd):
|
||||
"""Run a command and return its resolt"""
|
||||
print (cmd)
|
||||
return subprocess.call(cmd, shell=True)
|
||||
|
||||
def module_name(source_name):
|
||||
"""Get module name of a source file (currently this only depends on its path)"""
|
||||
return os.path.splitext(source_name)[0].replace("/", ".")
|
||||
|
||||
def scan_sources(source_dir, ignore):
|
||||
"""Get a list of relative paths all source files in specified directory."""
|
||||
sources = []
|
||||
for root, dirs, files in os.walk(source_dir):
|
||||
for filename in files:
|
||||
def add_source():
|
||||
if os.path.splitext(filename)[1] not in [".d", ".dd", ".ddoc"]:
|
||||
return
|
||||
source = os.path.join(root, filename)
|
||||
if source.startswith("./"):
|
||||
source = source[2:]
|
||||
for exp in ignore:
|
||||
try:
|
||||
if(re.compile(exp.strip()).match(source)):
|
||||
return
|
||||
except re.error as error:
|
||||
print("Ignore expression is not a valid regexp: ", exp,
|
||||
"error:", error)
|
||||
raise error
|
||||
sources.append(source);
|
||||
add_source()
|
||||
return sorted(sources, key=str.lower)
|
||||
|
||||
def add_template(template_path, sources, links, project):
|
||||
"""Generate DDoc template file at template_path,
|
||||
connecting to sources and links, using specified project data."""
|
||||
with open(template_path, mode="w", encoding="utf-8") as a_file:
|
||||
a_file.write(template_macros)
|
||||
|
||||
#Project info.
|
||||
a_file.write("PROJECT_NAME= " + project.name + "\n")
|
||||
a_file.write("PROJECT_VERSION= " + project.version + "\n")
|
||||
a_file.write("COPYRIGHT= ")
|
||||
if project.copyright is not None and project.copyright != "":
|
||||
a_file.write("Copyright © " + project.copyright)
|
||||
a_file.write("\n")
|
||||
|
||||
|
||||
#DDOC macro - this is the template itself, using other macros.
|
||||
a_file.write("DDOC = <!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n"
|
||||
" \"http://www.w3.org/TR/html4/strict.dtd\">\n")
|
||||
a_file.write(template_header)
|
||||
a_file.write("<body>")
|
||||
|
||||
#Heading and the logo, if any.
|
||||
top = ("<div id=\"top\">\n"
|
||||
"<div id=\"header\">\n")
|
||||
if project.logo_file is not None and project.logo_file != "":
|
||||
top += ("<img id=\"logo\" alt=\"" +
|
||||
project.name + " logo\" src=\"images/logo.png\">")
|
||||
top += ("<a id=\"main-heading\" href=\"index.html\">"
|
||||
"$(PROJECT_NAME) $(PROJECT_VERSION) API documentation</a>\n"
|
||||
"</div>\n</div>\n\n")
|
||||
a_file.write(top)
|
||||
|
||||
#Menu - user specified links.
|
||||
navigation = ("<div id=\"navigation\">\n"
|
||||
"<div class=\"navblock\">\n"
|
||||
"<div id=\"toctop\">\n"
|
||||
"$(UL\n")
|
||||
for link, name in links:
|
||||
navigation += "$(LI $(LINK2 " + link + ", " + name + "))\n"
|
||||
navigation += ")\n</div>\n</div>\n"
|
||||
|
||||
#Menu -links to the modules.
|
||||
navigation += "<div class=\"navblock\">\n$(UL\n"
|
||||
navigation += "$(LI $(LINK2 index.html, Main page))\n"
|
||||
for source in sources:
|
||||
module = module_name(source)
|
||||
link = "$(LI $(LINK2 " + module + ".html," + module + "))\n"
|
||||
navigation += link
|
||||
navigation += ")\n</div>\n</div>\n\n"
|
||||
|
||||
a_file.write(navigation)
|
||||
|
||||
#Main content.
|
||||
content = "<div id=\"content\">\n<h1>$(TITLE)</h1>\n$(BODY)\n</div>\n"
|
||||
a_file.write(content)
|
||||
|
||||
a_file.write(template_footer)
|
||||
a_file.write("</body>\n</html>\n")
|
||||
|
||||
def add_logo(project, output_dir):
|
||||
"""Copy the logo, if any, to images/logo.png ."""
|
||||
if(project.logo_file is None or project.logo_file == ""):
|
||||
return
|
||||
images_path = os.path.join(output_dir, "images")
|
||||
os.makedirs(images_path, exist_ok=True)
|
||||
shutil.copy(project.logo_file, os.path.join(images_path, "logo.png"))
|
||||
|
||||
def generate_style(filename):
|
||||
"""Write default css to a file"""
|
||||
with open(filename, mode="w", encoding="utf-8") as a_file:
|
||||
a_file.write(default_css)
|
||||
|
||||
def add_css(css, output_dir):
|
||||
"""Copy the CSS if specified, write default CSS otherwise."""
|
||||
css_path = os.path.join(output_dir, "css")
|
||||
os.makedirs(css_path, exist_ok=True)
|
||||
css_path = os.path.join(css_path, "style.css")
|
||||
if css is None or css == "":
|
||||
generate_style(css_path)
|
||||
return
|
||||
shutil.copy(css, css_path)
|
||||
|
||||
def generate_index(filename):
|
||||
"""Write default index to a file"""
|
||||
with open(filename, mode="w", encoding="utf-8") as a_file:
|
||||
a_file.write("Ddoc\n\n")
|
||||
a_file.write("Macros:\n")
|
||||
a_file.write(" TITLE=$(PROJECT_NAME) $(PROJECT_VERSION) API documentation\n\n")
|
||||
|
||||
def add_index(index, output_dir):
|
||||
"""Copy the index if specified, write default index otherwise."""
|
||||
index_path = os.path.join(output_dir, "index.dd")
|
||||
if index is None or index == "":
|
||||
generate_index(index_path)
|
||||
return
|
||||
shutil.copy(index, index_path)
|
||||
|
||||
def generate_ddoc(sources, output_dir, ddoc_template, ddoc_command):
|
||||
"""Generate documentation from sources, writing it to output_dir."""
|
||||
|
||||
#Generate index html with ddoc.
|
||||
index_ddoc = os.path.join(output_dir, "index.dd")
|
||||
index_html = os.path.join(output_dir, "index.html")
|
||||
run_cmd(ddoc_command + " -Df" + index_html + " " + index_ddoc)
|
||||
os.remove(index_ddoc)
|
||||
|
||||
#Now generate html for the sources.
|
||||
for source in sources:
|
||||
out_path = os.path.join(output_dir, module_name(source)) + ".html"
|
||||
run_cmd(ddoc_command + " -Df" + out_path + " " + source)
|
||||
|
||||
def generate_config(filename):
|
||||
"""Generate default AutoDDoc config file."""
|
||||
with open(filename, mode="w", encoding="utf-8") as a_file:
|
||||
a_file.write(default_cfg)
|
||||
|
||||
def init_parser():
|
||||
"""Initialize and return the command line parser."""
|
||||
autoddoc_description =\
|
||||
("AutoDDoc 0.1\n"
|
||||
"Documentation generator script for D using DDoc.\n"
|
||||
"Copyright Ferdinand Majerech 2011.\n\n"
|
||||
"AutoDDoc scans subdirectories of the current directory for D or DDoc\n"
|
||||
"sources (.d, .dd or .ddoc) and generates documentation using settings\n"
|
||||
"from a configuration file.\n"
|
||||
"NOTE: AutoDDoc will only work if package/module hierarchy matches the\n"
|
||||
"directory hierarchy, so e.g. module 'pkg.util' would be in file './pkg/util.d' .")
|
||||
|
||||
autoddoc_epilog =\
|
||||
("\nTutorial:\n"
|
||||
"1. Copy the script to your project directory and move into that directory.\n"
|
||||
" Relative to this directory, module names must match their filenames,\n"
|
||||
" so e.g. module 'pkg.util' would be in file './pkg/util.d' .\n"
|
||||
"2. Generate AutoDDoc configuation file. To do this, type\n"
|
||||
" './autoddoc.py -g'. This will generate file 'autoddoc.cfg' .\n"
|
||||
"3. Edit the configuation file. Set project name, version, output\n"
|
||||
" directory and other parameters.\n"
|
||||
"4. Generate the documentation by typing './autoddoc.py' .\n")
|
||||
|
||||
parser = argparse.ArgumentParser(description= autoddoc_description,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog = autoddoc_epilog, add_help=True)
|
||||
|
||||
parser.add_argument("config_file", nargs="?", default="autoddoc.cfg",
|
||||
help="Configuration file to use to generate documentation. "
|
||||
"Can not be used with any optional arguments. "
|
||||
"If not specified, 'autoddoc.cfg' is assumed. "
|
||||
"Examples: 'autoddoc.py config.cfg' "
|
||||
"will generate documentation using file 'config.cfg' . "
|
||||
"'autoddoc.py' will generate documentation "
|
||||
"using file 'autoddoc.cfg' if it exists.",
|
||||
metavar="config_file")
|
||||
parser.add_argument("-g", "--gen-config", nargs="?", const="autoddoc.cfg",
|
||||
help="Generate default AutoDDoc configuation file. "
|
||||
"config_file is the filename to use. If not specified, "
|
||||
"autoddoc.cfg is used.",
|
||||
metavar="config_file")
|
||||
parser.add_argument("-s", "--gen-style", nargs="?", const="autoddoc_style.css",
|
||||
help="Generate default AutoDDoc style sheet. "
|
||||
"css_file is the filename to use. If not specified, "
|
||||
"autoddoc_style.css is used.",
|
||||
metavar="css_file")
|
||||
parser.add_argument("-i", "--gen-index", nargs="?", const="autoddoc_index.dd",
|
||||
help="Generate default AutoDDoc documentation index. "
|
||||
"index_file is the filename to use. If not specified, "
|
||||
"autoddoc_index.dd is used.",
|
||||
metavar="index_file")
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def main():
|
||||
parser = init_parser()
|
||||
args = parser.parse_args()
|
||||
|
||||
#Generate config/style/index if requested.
|
||||
done = False;
|
||||
try:
|
||||
if args.gen_config is not None:
|
||||
generate_config(args.gen_config)
|
||||
done = True
|
||||
if args.gen_style is not None:
|
||||
generate_style(args.gen_style)
|
||||
done = True
|
||||
if args.gen_index is not None:
|
||||
generate_index(args.gen_index)
|
||||
done = True
|
||||
except IOError as error:
|
||||
print("\nERROR: Unable to generate:", error)
|
||||
return
|
||||
|
||||
if done or args.config_file is None:
|
||||
return
|
||||
|
||||
if not os.path.isfile(args.config_file):
|
||||
print("\nERROR: Can't find configuration file", args.config_file, "\n")
|
||||
parser.print_help()
|
||||
return
|
||||
|
||||
#Load documentation config.
|
||||
config = configparser.ConfigParser()
|
||||
try:
|
||||
config.read(args.config_file)
|
||||
|
||||
project = config["PROJECT"]
|
||||
project = ProjectInfo(project["name"],
|
||||
project["version"],
|
||||
project["copyright"],
|
||||
project["logo"])
|
||||
|
||||
output = config["OUTPUT"]
|
||||
output_dir = output["directory"]
|
||||
if output_dir == "":
|
||||
output_dir = "autoddoc"
|
||||
css = output["style"]
|
||||
index = output["index"]
|
||||
links = []
|
||||
if output["links"] != "":
|
||||
for link in output["links"].split(","):
|
||||
parts = link.split(" ", 1)
|
||||
links.append((parts[0].strip(), parts[1].strip()))
|
||||
ignore = output["ignore"].split(",")
|
||||
if ignore == [""]:
|
||||
ignore = []
|
||||
|
||||
ddoc_line = config["DDOC"]["ddoc_command"]
|
||||
except configparser.Error as error:
|
||||
print("Unable to parse configuration file", args.config_file, ":", error)
|
||||
return
|
||||
except IOError as error:
|
||||
print("Unable to read configuration file", args.config_file, ":", error)
|
||||
return
|
||||
|
||||
#Do the actual generation work.
|
||||
try:
|
||||
#Find all .d, .dd, .ddoc files.
|
||||
sources = scan_sources(".", ignore)
|
||||
ddoc_template = os.path.join(output_dir, "AUTODDOC_TEMPLATE.ddoc")
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
add_template(ddoc_template, sources, links, project)
|
||||
add_logo(project, output_dir)
|
||||
add_css(css, output_dir)
|
||||
add_index(index, output_dir)
|
||||
|
||||
generate_ddoc(sources, output_dir, ddoc_template, ddoc_line + " " + ddoc_template);
|
||||
os.remove(ddoc_template)
|
||||
except Exception as error:
|
||||
print("Error during documentation generation:", error)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
663
cdc.d
Executable file
|
@ -0,0 +1,663 @@
|
|||
#!/usr/bin/rdmd
|
||||
|
||||
/**
|
||||
* License: Boost 1.0
|
||||
*
|
||||
* Copyright (c) 2009-2010 Eric Poggel, Changes 2011 Ferdinand Majerech
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* This is a D programming language build script (and library) that can be used
|
||||
* to compile D (version 1) source code. Unlike Bud, DSSS/Rebuild, Jake, and
|
||||
* similar tools, CDC is contained within a single file that can easily be
|
||||
* distributed with projects. This simplifies the build process since no other
|
||||
* tools are required. The main() function can be utilized to turn
|
||||
* CDC into a custom build script for your project.
|
||||
*
|
||||
* CDC's only requirement is a D compiler. It is/will be supported on any
|
||||
* operating system supported by the language. It works with dmd, ldc (soon),
|
||||
* and gdc.
|
||||
*
|
||||
* CDC can be used just like dmd, except for the following improvements.
|
||||
* <ul>
|
||||
* <li>CDC can accept paths as as well as individual source files for compilation.
|
||||
* Each path is recursively searched for source, library, object, and ddoc files.</li>
|
||||
* <li>CDC automatically creates a modules.ddoc file for use with CandyDoc and
|
||||
* similar documentation utilities.</li>
|
||||
* <li>CDC defaults to use the compiler that was used to build itself. Compiler
|
||||
* flags are passed straight through to that compiler.</li>
|
||||
* <li>The -op flag is always used, to prevent name conflicts in object and doc files.</li>
|
||||
* <li>Documentation files are all placed in the same folder with their full package
|
||||
* names. This makes relative links between documents easier.</li>
|
||||
* </ul>
|
||||
|
||||
* These DMD/LDC options are automatically translated to the correct GDC
|
||||
* options, or handled manually:
|
||||
* <dl>
|
||||
* <dt>-c</dt> <dd>do not link</dd>
|
||||
* <dt>-D</dt> <dd>generate documentation</dd>
|
||||
* <dt>-Dddocdir</dt> <dd>write fully-qualified documentation files to docdir directory</dd>
|
||||
* <dt>-Dfdocfile</dt> <dd>write fully-qualified documentation files to docfile file</dd>
|
||||
* <dt>-lib</dt> <dd>Generate library rather than object files</dd>
|
||||
* <dt>-Ipath</dt> <dd>where to look for imports</dd>
|
||||
* <dt>-o-</dt> <dd>do not write object file.</dd>
|
||||
* <dt>-offilename</dt><dd>name output file to filename</dd>
|
||||
* <dt>-odobjdir</dt> <dd>write object & library files to directory objdir</dd>
|
||||
* </dl>
|
||||
*
|
||||
* In addition, these optional flags have been added.
|
||||
* <dl>
|
||||
* <dt>--dmd</dt> <dd>Use dmd to compile</dd>
|
||||
* <dt>--gdc</dt> <dd>Use gdc to compile</dd>
|
||||
* <dt>--ldc</dt> <dd>Use ldc to compile</dd>
|
||||
* </dl>
|
||||
*
|
||||
* Bugs:
|
||||
* <ul>
|
||||
* <li>Doesn't yet work with LDC. See dsource.org/projects/ldc/ticket/323</li>
|
||||
* <li>Dmd writes out object files as foo/bar.o, while gdc writes foo.bar.o</li>
|
||||
* <li>Dmd fails to write object files when -od is an absolute path.</li>
|
||||
* </ul>
|
||||
*
|
||||
* TODO:
|
||||
* <ul>
|
||||
* <li>Add support for a --script argument to accept another .d file that calls cdc's functions.</li>
|
||||
* <li>-Df option</li>
|
||||
* <li>GDC - Remove dependancy on "ar" on windows? </li>
|
||||
* <li>LDC - Scanning a folder for files is broken. </li>
|
||||
* <li>Unittests</li>
|
||||
* <li>More testing on paths with spaces. </li>
|
||||
* </ul>
|
||||
*
|
||||
* API:
|
||||
* Use any of these functions in your own build script.
|
||||
*/
|
||||
|
||||
|
||||
import std.algorithm;
|
||||
import std.array;
|
||||
import std.exception;
|
||||
import std.conv;
|
||||
import std.file;
|
||||
import std.path;
|
||||
import std.process;
|
||||
import std.range;
|
||||
import std.string;
|
||||
import std.stdio : writeln;
|
||||
|
||||
|
||||
///Name of the default compiler, which is the compiler used to build cdc.
|
||||
version(DigitalMars){string compiler = "dmd";}
|
||||
version(GNU){string compiler = "gdmd";}
|
||||
version(LDC){string compiler = "ldmd";}
|
||||
|
||||
version(Windows)
|
||||
{
|
||||
///Valid object file extensions.
|
||||
const string[] obj_ext = ["obj", "o"];
|
||||
///Library extension.
|
||||
const string lib_ext = "lib";
|
||||
///Binary executable extension.
|
||||
const string bin_ext = "exe";
|
||||
///Path separator character.
|
||||
char file_separator ='\\';
|
||||
}
|
||||
else
|
||||
{
|
||||
///Valid object file extensions.
|
||||
const string[] obj_ext = ["o"];
|
||||
///Library extension.
|
||||
const string lib_ext = "a";
|
||||
///Binary executable extension.
|
||||
const string bin_ext = "";
|
||||
///Path separator character.
|
||||
char file_separator ='/';
|
||||
}
|
||||
|
||||
void main(string[] args)
|
||||
{
|
||||
string target = "release";
|
||||
|
||||
scope(failure){help(); core.stdc.stdlib.exit(-1);}
|
||||
|
||||
string[] extra_args = ["-w", "-wi"];
|
||||
|
||||
args = args[1 .. $];
|
||||
foreach(arg; args)
|
||||
{
|
||||
if(arg[0] == '-')
|
||||
{
|
||||
switch(arg)
|
||||
{
|
||||
case "--help", "-h": help(); return;
|
||||
case "--dmd": compiler = "dmd"; break;
|
||||
case "--gdc": compiler = "gdmd"; break;
|
||||
case "--ldc": compiler = "ldmd"; break;
|
||||
default: extra_args ~= arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(args.length > 0 && args[$ - 1][0] != '-'){target = args[$ - 1];}
|
||||
|
||||
string[] dbg = ["-gc", "-debug"];
|
||||
string[] optimize = ["-O", "-inline", "-release"];
|
||||
string[] lib_src = ["dyaml/", "yaml.d"];
|
||||
|
||||
void compile_(string[] args, string[] files){compile(files, args ~ extra_args);}
|
||||
|
||||
void build_unittest()
|
||||
{
|
||||
writeln("building unittests");
|
||||
compile_(dbg ~ ["-unittest", "-ofunittest"], lib_src ~ "unittest.d" ~ "test/src");
|
||||
}
|
||||
|
||||
void build_debug()
|
||||
{
|
||||
writeln("building debug target");
|
||||
compile_(dbg ~ ["-oflibdyaml-debug", "-lib"], lib_src);
|
||||
}
|
||||
|
||||
void build_release()
|
||||
{
|
||||
writeln("building release target");
|
||||
compile_(optimize ~ ["-oflibdyaml", "-lib"], lib_src);
|
||||
}
|
||||
|
||||
void build_tar_gz()
|
||||
{
|
||||
if(system("tar cf dyaml.tar * && gzip -9v dyaml.tar ") != 0)
|
||||
{
|
||||
writeln("Error creating a tar.gz package.");
|
||||
}
|
||||
}
|
||||
|
||||
void build_tar_xz()
|
||||
{
|
||||
if(system("tar cf dyaml.tar * && xz -9ev dyaml.tar ") != 0)
|
||||
{
|
||||
writeln("Error creating a tar.xz package.");
|
||||
}
|
||||
}
|
||||
|
||||
void build(string[] targets ...)
|
||||
{
|
||||
foreach(target; targets)
|
||||
{
|
||||
switch(target)
|
||||
{
|
||||
//case "examples": build_examples(); break;
|
||||
case "debug": build_debug(); break;
|
||||
case "release": build_release(); break;
|
||||
case "unittest": build_unittest(); break;
|
||||
case "tar.gz": build_tar_gz(); break;
|
||||
case "tar.xz": build_tar_xz(); break;
|
||||
case "all": build("debug", "release", "unittest"); break;
|
||||
default:
|
||||
writeln("unknown build target: ", target);
|
||||
writeln("available targets: 'debug', 'release', 'all'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try{build(target);}
|
||||
catch(CompileException e){writeln("Could not compile: " ~ e.msg);}
|
||||
catch(ProcessException e){writeln("Compilation failed: " ~ e.msg);}
|
||||
}
|
||||
|
||||
///Print help information.
|
||||
void help()
|
||||
{
|
||||
string help =
|
||||
"D:YAML build script\n"
|
||||
"Changes Copyright (C) 2011 Ferdinand Majerech\n"
|
||||
"Based on CDC script Copyright (C) 2009-2010 Eric Poggel\n"
|
||||
"Usage: cdc [OPTION ...] [EXTRA COMPILER OPTION ...] [TARGET]\n"
|
||||
"By default, cdc uses the compiler it was built with to compile the project.\n"
|
||||
"\n"
|
||||
"Any options starting with '-' not parsed by the script will be\n"
|
||||
"passed to the compiler used.\n"
|
||||
"\n"
|
||||
"Optionally, build target can be specified, 'debug' is default.\n"
|
||||
"Available build targets:\n"
|
||||
" unittest Build unit tests.\n"
|
||||
" debug Debug information, unittests, contracts built in.\n"
|
||||
" No optimizations. Target binary name: 'pong-debug'\n"
|
||||
" release Debug information, no unittests, contracts.\n"
|
||||
" Optimizations, inlining enabled.\n"
|
||||
" Target binary name: 'pong-release'\n"
|
||||
" all All of the above.\n"
|
||||
" tar.gz Unix/Linux only: Create a tar.gz package\n"
|
||||
" (this just archives the directory at the moment)\n"
|
||||
" tar.xz Unix/Linux only: Create a tar.xz package\n"
|
||||
" (this just archives the directory at the moment)\n"
|
||||
"\n"
|
||||
"Available options:\n"
|
||||
" -h --help Show this help information.\n"
|
||||
" --gdc Use GDC for compilation.\n"
|
||||
" --dmd Use DMD for compilation.\n"
|
||||
" --ldc Use LDC for compilation. (not tested)\n"
|
||||
;
|
||||
writeln(help);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile D code using the current compiler.
|
||||
*
|
||||
* Params: paths = Source and library files/directories. Directories are recursively searched.
|
||||
* options = Compiler options.
|
||||
*
|
||||
* Example:
|
||||
* --------
|
||||
* //Compile all source files in src/core along with src/main.d,
|
||||
* //link with all library files in the libs folder
|
||||
* //and generate documentation in the docs folder.
|
||||
* compile(["src/core", "src/main.d", "libs"], ["-D", "-Dddocs"]);
|
||||
* --------
|
||||
*
|
||||
* TODO Add a dry run option to just return an array of commands to execute.
|
||||
*/
|
||||
static void compile(string[] paths, string[] options = null)
|
||||
{
|
||||
//Convert src and lib paths to files
|
||||
string[] sources, libs, ddocs;
|
||||
foreach(src; paths)
|
||||
{
|
||||
enforceEx!CompileException(exists(src),
|
||||
"Source file/folder \"" ~ src ~ "\" does not exist.");
|
||||
//Directory of source or lib files
|
||||
if(isdir(src))
|
||||
{
|
||||
sources ~= scan(src, ".d");
|
||||
ddocs ~= scan(src, ".ddoc");
|
||||
libs ~= scan(src, lib_ext);
|
||||
}
|
||||
//File
|
||||
else if(isfile(src))
|
||||
{
|
||||
string ext = "." ~ src.getExt();
|
||||
if(ext == ".d"){sources ~= src;}
|
||||
else if(ext == lib_ext){libs ~= src;}
|
||||
}
|
||||
}
|
||||
|
||||
//Add dl.a for dynamic linking on linux
|
||||
version(linux){libs ~= ["-L-ldl"];}
|
||||
|
||||
//Combine all options, sources, ddocs, and libs
|
||||
CompileOptions co = CompileOptions(options, sources);
|
||||
options = co.get_options(compiler);
|
||||
|
||||
if(compiler == "gdc")
|
||||
{
|
||||
foreach(ref d; ddocs){d = "-fdoc-inc=" ~ d;}
|
||||
//or should this only be version(Windows) ?
|
||||
//TODO: Check in dmd and gdc
|
||||
foreach(ref l; libs){l = "-L" ~ l;}
|
||||
}
|
||||
|
||||
//Create modules.ddoc and add it to array of ddocs
|
||||
if(co.generate_doc)
|
||||
{
|
||||
string modules = "MODULES = \r\n";
|
||||
sources.sort;
|
||||
foreach(src; sources)
|
||||
{
|
||||
//get filename
|
||||
src = split(src, "\\.")[0];
|
||||
src = replace(replace(src, "/", "."), "\\", ".");
|
||||
modules ~= "\t$(MODULE " ~ src ~ ")\r\n";
|
||||
}
|
||||
scope(failure){remove("modules.ddoc");}
|
||||
write("modules.ddoc", modules);
|
||||
ddocs ~= "modules.ddoc";
|
||||
}
|
||||
|
||||
string[] arguments = options ~ sources ~ ddocs ~ libs;
|
||||
|
||||
//Compile
|
||||
if(compiler == "gdc")
|
||||
{
|
||||
//Add support for building libraries to gdc.
|
||||
//GDC must build incrementally if creating documentation or a lib.
|
||||
if(co.generate_lib || co.generate_doc || co.no_linking)
|
||||
{
|
||||
//Remove options we don't want to pass to gdc when building incrementally.
|
||||
string[] incremental_options;
|
||||
foreach(option; options)
|
||||
{
|
||||
if(option != "-lib" && !startsWith(option, "-o"))
|
||||
{
|
||||
incremental_options ~= option;
|
||||
}
|
||||
}
|
||||
|
||||
//Compile files individually, outputting full path names
|
||||
string[] obj_files;
|
||||
foreach(source; sources)
|
||||
{
|
||||
string obj = replace(source, "/", ".")[0 .. $ - 2] ~ ".o";
|
||||
string ddoc = obj[0 .. $ - 2];
|
||||
if(co.obj_directory !is null)
|
||||
{
|
||||
obj = co.obj_directory ~ file_separator ~ obj;
|
||||
}
|
||||
obj_files ~= obj;
|
||||
string[] exec = incremental_options ~ ["-o" ~ obj, "-c"] ~ [source];
|
||||
//ensure doc files are always fully qualified.
|
||||
if(co.generate_doc){exec ~= ddocs ~ ["-fdoc-file=" ~ ddoc ~ ".html"];}
|
||||
//throws ProcessException on compile failure
|
||||
execute(compiler, exec);
|
||||
}
|
||||
|
||||
//use ar to join the .o files into a lib and cleanup obj files
|
||||
//TODO: how to join on GDC windows?
|
||||
if(co.generate_lib)
|
||||
{
|
||||
//since ar refuses to overwrite it.
|
||||
remove(co.out_file);
|
||||
execute("ar", "cq " ~ co.out_file ~ obj_files);
|
||||
}
|
||||
|
||||
//Remove obj files if -c or -od not were supplied.
|
||||
if(!co.obj_directory && !co.no_linking)
|
||||
{
|
||||
foreach (o; obj_files){remove(o);}
|
||||
}
|
||||
}
|
||||
|
||||
if (!co.generate_lib && !co.no_linking)
|
||||
{
|
||||
//Remove documentation arguments since they were handled above
|
||||
string[] nondoc_args;
|
||||
foreach(arg; arguments)
|
||||
{
|
||||
if(!startsWith(arg, "-fdoc", "-od")){nondoc_args ~= arg;}
|
||||
}
|
||||
|
||||
execute_compiler(compiler, nondoc_args);
|
||||
}
|
||||
}
|
||||
//Compilers other than gdc
|
||||
else
|
||||
{
|
||||
execute_compiler(compiler, arguments);
|
||||
//Move all html files in doc_path to the doc output folder
|
||||
//and rename them with the "package.module" naming convention.
|
||||
if(co.generate_doc)
|
||||
{
|
||||
foreach(src; sources)
|
||||
{
|
||||
if(src.getExt != "d"){continue;}
|
||||
|
||||
string html = src[0 .. $ - 2] ~ ".html";
|
||||
string dest = replace(replace(html, "/", "."), "\\", ".");
|
||||
if(co.doc_directory.length > 0)
|
||||
{
|
||||
dest = co.doc_directory ~ file_separator ~ dest;
|
||||
html = co.doc_directory ~ file_separator ~ html;
|
||||
}
|
||||
//TODO: Delete remaining folders where source files were placed.
|
||||
if(html != dest)
|
||||
{
|
||||
copy(html, dest);
|
||||
remove(html);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Remove extra files
|
||||
string basename = split(co.out_file, "/")[$ - 1];
|
||||
|
||||
if(co.generate_doc){remove("modules.ddoc");}
|
||||
if(co.out_file && !(co.no_linking || co.obj_directory))
|
||||
{
|
||||
foreach(ext; obj_ext)
|
||||
{
|
||||
//Delete object files with same name as output file that dmd sometimes leaves.
|
||||
try{remove(addExt(co.out_file, ext));}
|
||||
catch(FileException e){continue;}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores compiler options and translates them between compilers.
|
||||
*
|
||||
* Also enables -of and -op for easier handling.
|
||||
*/
|
||||
struct CompileOptions
|
||||
{
|
||||
public:
|
||||
///Do not link.
|
||||
bool no_linking;
|
||||
///Generate documentation.
|
||||
bool generate_doc;
|
||||
///Write documentation to this directory.
|
||||
string doc_directory;
|
||||
///Write documentation to this file.
|
||||
string doc_file;
|
||||
///Generate library rather than object files.
|
||||
bool generate_lib;
|
||||
///Do not write object files.
|
||||
bool no_objects;
|
||||
///write object, library files to this directory.
|
||||
string obj_directory;
|
||||
///Name of output file.
|
||||
string out_file;
|
||||
|
||||
private:
|
||||
///Compiler options.
|
||||
string[] options_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct CompileOptions from command line options.
|
||||
*
|
||||
* Params: options = Compiler command line options.
|
||||
* sources = Source files to compile.
|
||||
*/
|
||||
this(string[] options, in string[] sources)
|
||||
{
|
||||
foreach (i, option; options)
|
||||
{
|
||||
if(option == "-c"){no_linking = true;}
|
||||
else if(option == "-D" || option == "-fdoc"){generate_doc = true;}
|
||||
else if(startsWith(option, "-Dd")){doc_directory = option[3..$];}
|
||||
else if(startsWith(option, "-fdoc-dir=")){doc_directory = option[10..$];}
|
||||
else if(startsWith(option, "-Df")){doc_file = option[3..$];}
|
||||
else if(startsWith(option, "-fdoc-file=")){doc_file = option[11..$];}
|
||||
else if(option == "-lib"){generate_lib = true;}
|
||||
else if(option == "-o-" || option=="-fsyntax-only"){no_objects = true;}
|
||||
else if(startsWith(option, "-of")){out_file = option[3..$];}
|
||||
else if(startsWith(option, "-od")){obj_directory = option[3..$];}
|
||||
else if(startsWith(option, "-o") && option != "-op"){out_file = option[2..$];}
|
||||
options_ ~= option;
|
||||
}
|
||||
|
||||
//Set the -o (output filename) flag to the first source file if not already set.
|
||||
//This matches the default behavior of dmd.
|
||||
string ext = generate_lib ? lib_ext : bin_ext;
|
||||
if(out_file.length == 0 && !no_linking && !no_objects && sources.length > 0)
|
||||
{
|
||||
out_file = split(split(sources[0], "/")[$ - 1], "\\.")[0] ~ ext;
|
||||
options_ ~= ("-of" ~ out_file);
|
||||
}
|
||||
version (Windows)
|
||||
{
|
||||
//TODO needs testing
|
||||
//{ if (find(this.out_file, ".") <= rfind(this.out_file, "/"))
|
||||
if(find(out_file, '.') <= retro(find(retro(out_file), '/')))
|
||||
{
|
||||
out_file ~= bin_ext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate DMD compiler options to options of the target compiler.
|
||||
*
|
||||
* This function is incomplete. (what about -L? )
|
||||
*
|
||||
* Params: compiler = Compiler to translate to.
|
||||
*
|
||||
* Returns: Translated options.
|
||||
*/
|
||||
string[] get_options(in string compiler)
|
||||
{
|
||||
string[] result = options_.dup;
|
||||
|
||||
if(compiler != "gdc")
|
||||
{
|
||||
version(Windows)
|
||||
{
|
||||
foreach(ref option; result)
|
||||
{
|
||||
option = startsWith(option, "-of") ? replace(option, "/", "\\") : option;
|
||||
}
|
||||
}
|
||||
|
||||
//ensure ddocs don't overwrite one another.
|
||||
return canFind(result, "-op") ? result : result ~ "-op";
|
||||
}
|
||||
|
||||
//is gdc
|
||||
string[string] translate;
|
||||
translate["-Dd"] = "-fdoc-dir=";
|
||||
translate["-Df"] = "-fdoc-file=";
|
||||
translate["-debug="] = "-fdebug=";
|
||||
translate["-debug"] = "-fdebug"; // will this still get selected?
|
||||
translate["-inline"] = "-finline-functions";
|
||||
translate["-L"] = "-Wl";
|
||||
translate["-lib"] = "";
|
||||
translate["-O"] = "-O3";
|
||||
translate["-o-"] = "-fsyntax-only";
|
||||
translate["-of"] = "-o ";
|
||||
translate["-unittest"] = "-funittest";
|
||||
translate["-version"] = "-fversion=";
|
||||
translate["-version="] = "-fversion=";
|
||||
translate["-wi"] = "-Wextra";
|
||||
translate["-w"] = "-Wall";
|
||||
translate["-gc"] = "-g";
|
||||
|
||||
//Perform option translation
|
||||
foreach(ref option; result)
|
||||
{
|
||||
//remove unsupported -od
|
||||
if(startsWith(option, "-od")){option = "";}
|
||||
if(option =="-D"){option = "-fdoc";}
|
||||
else
|
||||
{
|
||||
//Options with a direct translation
|
||||
foreach(before, after; translate)
|
||||
{
|
||||
if(startsWith(option, before))
|
||||
{
|
||||
option = after ~ option[before.length..$];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
unittest
|
||||
{
|
||||
auto sources = ["foo.d"];
|
||||
auto options = ["-D", "-inline", "-offoo"];
|
||||
auto result = CompileOptions(options, sources).get_options("gdc");
|
||||
assert(result[0 .. 3] == ["-fdoc", "-finline-functions", "-o foo"]);
|
||||
}
|
||||
}
|
||||
|
||||
///Thrown at errors in execution of other processes (e.g. compiler commands).
|
||||
class CompileException : Exception {this(in string message){super(message);}};
|
||||
|
||||
/**
|
||||
* Wrapper around execute to write compile options to a file to get around max arg lenghts on Windows.
|
||||
*
|
||||
* Params: compiler = Compiler to execute.
|
||||
* arguments = Compiler arguments.
|
||||
*/
|
||||
void execute_compiler(in string compiler, string[] arguments)
|
||||
{
|
||||
try
|
||||
{
|
||||
version(Windows)
|
||||
{
|
||||
write("compile", join(arguments, " "));
|
||||
scope(exit){remove("compile");}
|
||||
execute(compiler ~ " ", ["@compile"]);
|
||||
}
|
||||
else{execute(compiler, arguments);}
|
||||
}
|
||||
catch(ProcessException e)
|
||||
{
|
||||
writeln("Compiler failed: " ~ e.msg);
|
||||
}
|
||||
}
|
||||
|
||||
///Thrown at errors in execution of other processes (e.g. compiler commands).
|
||||
class ProcessException : Exception {this(in string message){super(message);}};
|
||||
|
||||
/**
|
||||
* Execute a command-line program and print its output.
|
||||
*
|
||||
* Params: command = The command to execute, e.g. "dmd".
|
||||
* args = Arguments to pass to the command.
|
||||
*
|
||||
* Throws: ProcessException on failure or status code 1.
|
||||
*/
|
||||
void execute(string command, string[] args)
|
||||
{
|
||||
version(Windows)
|
||||
{
|
||||
if(startsWith(command, "./")){command = command[2 .. $];}
|
||||
}
|
||||
|
||||
string full = command ~ " " ~ join(args, " ");
|
||||
writeln("CDC: " ~ full);
|
||||
if(int status = system(full) != 0)
|
||||
{
|
||||
throw new ProcessException("Process " ~ command ~ " exited with status " ~
|
||||
to!string(status));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively get all files with specified extensions in directory and subdirectories.
|
||||
*
|
||||
* Params: directory = Absolute or relative path to the current directory.
|
||||
* extensions = Extensions to match.
|
||||
*
|
||||
* Returns: An array of paths (including filename) relative to directory.
|
||||
*
|
||||
* Bugs: LDC fails to return any results.
|
||||
*/
|
||||
string[] scan(in string directory, string extensions ...)
|
||||
{
|
||||
string[] result;
|
||||
foreach(string name; dirEntries(directory, SpanMode.depth))
|
||||
{
|
||||
if(isfile(name) && endsWith(name, extensions)){result ~= name;}
|
||||
}
|
||||
return result;
|
||||
}
|
BIN
doc/doctrees/articles/spec_differences.doctree
Normal file
BIN
doc/doctrees/environment.pickle
Normal file
BIN
doc/doctrees/index.doctree
Normal file
BIN
doc/doctrees/tutorials/custom_types.doctree
Normal file
BIN
doc/doctrees/tutorials/getting_started.doctree
Normal file
BIN
doc/doctrees/tutorials/yaml_syntax.doctree
Normal file
4
doc/html/.buildinfo
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Sphinx build info version 1
|
||||
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
|
||||
config: bc848a1b422611af46aa082001644165
|
||||
tags: fbb0d17656682115ca4d033fb2f83ba1
|
65
doc/html/_sources/articles/spec_differences.txt
Normal file
|
@ -0,0 +1,65 @@
|
|||
.. highlight:: yaml
|
||||
|
||||
=====================================================
|
||||
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. D:YAML 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:
|
||||
|
||||
* At the moment, all mappings in the internal representation are ordered,
|
||||
and a comparison for equality between equal mappings with differing order
|
||||
will return false. This will be fixed once Phobos has a usable map type or
|
||||
D associative arrays work with variants.
|
||||
* 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.
|
21
doc/html/_sources/index.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
================================
|
||||
Welcome to D:YAML documentation!
|
||||
================================
|
||||
|
||||
`API Documentation <api/index.html>`_
|
||||
|
||||
Tutorials:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
tutorials/getting_started
|
||||
tutorials/custom_types
|
||||
tutorials/yaml_syntax
|
||||
|
||||
Articles:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
articles/spec_differences
|
227
doc/html/_sources/tutorials/custom_types.txt
Normal file
|
@ -0,0 +1,227 @@
|
|||
======================
|
||||
Custom YAML data types
|
||||
======================
|
||||
|
||||
Often you will want to serialize complex data types such as classes. You can use
|
||||
functions to process nodes; e.g. a mapping containing class data members indexed
|
||||
by name. Alternatively, YAML supports custom data types using 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, so you don't need to specify tag for each float, integer, etc.
|
||||
It is also possible to implicitly resolve custom tags, as we will show later.
|
||||
|
||||
|
||||
-----------
|
||||
Constructor
|
||||
-----------
|
||||
|
||||
D:YAML uses the *Constructor* class to process each node to hold data type
|
||||
corresponding to its tag. *Constructor* stores a function for each supported
|
||||
tag to process it. These functions can be supplied by the user using the
|
||||
*addConstructor()* method. *Constructor* is then passed to *Loader*, which will
|
||||
parse YAML input.
|
||||
|
||||
We will implement support for an RGB color type. It is implemented as the
|
||||
following struct:
|
||||
|
||||
.. code-block:: d
|
||||
|
||||
struct Color
|
||||
{
|
||||
ubyte red;
|
||||
ubyte green;
|
||||
ubyte blue;
|
||||
}
|
||||
|
||||
First, we need a function to construct our data type. It must take two *Mark*
|
||||
structs, which store position of the node in the file, and 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 functions to construct a color from a scalar, using HTML-like format,
|
||||
RRGGBB, or from a mapping, where we use the following format:
|
||||
{r:RRR, g:GGG, b:BBB} . Code of these functions:
|
||||
|
||||
.. code-block:: d
|
||||
|
||||
Color constructColorScalar(Mark start, Mark end, string value)
|
||||
{
|
||||
if(value.length != 6)
|
||||
{
|
||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
||||
}
|
||||
//We don't need to check for uppercase chars this way.
|
||||
value = value.toLower();
|
||||
|
||||
//Get value of a hex digit.
|
||||
uint hex(char c)
|
||||
{
|
||||
if(!std.ascii.isHexDigit(c))
|
||||
{
|
||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
||||
}
|
||||
|
||||
if(std.ascii.isDigit(c))
|
||||
{
|
||||
return c - '0';
|
||||
}
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
|
||||
Color result;
|
||||
result.red = cast(ubyte)(16 * hex(value[0]) + hex(value[1]));
|
||||
result.green = cast(ubyte)(16 * hex(value[2]) + hex(value[3]));
|
||||
result.blue = cast(ubyte)(16 * hex(value[4]) + hex(value[5]));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Color constructColorMapping(Mark start, Mark end, Node.Pair[] pairs)
|
||||
{
|
||||
int r, g, b;
|
||||
r = g = b = -1;
|
||||
bool error = pairs.length != 3;
|
||||
|
||||
foreach(ref pair; pairs)
|
||||
{
|
||||
//Key might not be a string, and value might not be an int,
|
||||
//so we need to check for that
|
||||
try
|
||||
{
|
||||
switch(pair.key.get!string)
|
||||
{
|
||||
case "r": r = pair.value.get!int; break;
|
||||
case "g": g = pair.value.get!int; break;
|
||||
case "b": b = pair.value.get!int; break;
|
||||
default: error = true;
|
||||
}
|
||||
}
|
||||
catch(NodeException e)
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
|
||||
{
|
||||
throw new ConstructorException("Invalid color", start, end);
|
||||
}
|
||||
|
||||
return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b);
|
||||
}
|
||||
|
||||
Next, we need some YAML code using our new tag. Create a file called input.yaml
|
||||
with the following contents:
|
||||
|
||||
.. code-block:: 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:
|
||||
|
||||
.. code-block:: d
|
||||
|
||||
void main()
|
||||
{
|
||||
auto red = Color(255, 0, 0);
|
||||
auto orange = Color(255, 255, 0);
|
||||
|
||||
try
|
||||
{
|
||||
auto constructor = new Constructor;
|
||||
//both functions handle the same tag, but one handles scalar, one mapping.
|
||||
constructor.addConstructor("!color", &constructColorScalar);
|
||||
constructor.addConstructor("!color-mapping", &constructColorMapping);
|
||||
|
||||
auto loader = new Loader("input.yaml", constructor, new Resolver);
|
||||
|
||||
auto root = loader.loadSingleDocument();
|
||||
|
||||
if(root["scalar-red"].get!Color == red &&
|
||||
root["mapping-red"].get!Color == red &&
|
||||
root["scalar-orange"].get!Color == orange &&
|
||||
root["mapping-orange"].get!Color == orange)
|
||||
{
|
||||
writeln("SUCCESS");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch(YAMLException e)
|
||||
{
|
||||
writeln(e.msg);
|
||||
}
|
||||
|
||||
writeln("FAILURE");
|
||||
}
|
||||
|
||||
First, we create a *Constructor* and pass functions to handle the ``!color``
|
||||
and ``!color-mapping`` tag. We construct a *Loader* using the *Constructor*.
|
||||
We also need a *Resolver*, but for now we just default-construct it. We then
|
||||
load the YAML document, and finally, read the colors using *get()* method to
|
||||
test if they were loaded as expected.
|
||||
|
||||
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 value can be tedious. D:YAML can implicitly
|
||||
resolve tag of a scalar using a regular expression. This is how default types,
|
||||
e.g. int, are resolved. We will use the *Resolver* 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 value must match to resolve to this tag, and a string of possible
|
||||
starting characters of the value. Then we pass the *Resolver* to the constructor
|
||||
of *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``.
|
||||
|
||||
.. code-block:: d
|
||||
|
||||
//code from the previous example...
|
||||
|
||||
auto resolver = new Resolver;
|
||||
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}",
|
||||
"0123456789abcdefABCDEF"));
|
||||
|
||||
auto loader = new Loader("input.yaml", constructor, resolver);
|
||||
|
||||
//code from the previous example...
|
||||
|
||||
Now, change contents of input.dyaml to this:
|
||||
|
||||
.. code-block:: 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.
|
168
doc/html/_sources/tutorials/getting_started.txt
Normal file
|
@ -0,0 +1,168 @@
|
|||
===============
|
||||
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://d-p-l.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 the
|
||||
information present might already be known to you. Only basic usage is covered.
|
||||
More advanced usage is described in other tutorials.
|
||||
|
||||
|
||||
----------
|
||||
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://www.digitalmars.com/d/download.html>`_.
|
||||
Download the version of DMD for your operating system and install it.
|
||||
|
||||
.. note::
|
||||
Other D compilers exist, such as
|
||||
`GDC <http://bitbucket.org/goshawk/gdc/wiki/Home>`_ and
|
||||
`LDC <http://www.dsource.org/projects/ldc/>`_.
|
||||
Setting up with either one of them should be similar to DMD,
|
||||
however, at the moment they are not as up to date as DMD.
|
||||
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Download and compile D:YAML
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The newest version of D:YAML can be found `here <TODO>`_. Download a source
|
||||
archive, extract it, and move to the extracted directory.
|
||||
|
||||
D:YAML uses a modified version of the `CDC <http://dsource.org/projects/cdc/>`_
|
||||
script for compilation. To compile D:YAML, you first need to build CDC.
|
||||
Do this by typing the following command into the console::
|
||||
|
||||
dmd cdc.d
|
||||
|
||||
Now you can use CDC to compile D:YAML.
|
||||
To do this on Unix/Linux, use the following command::
|
||||
|
||||
./cdc
|
||||
|
||||
On Windows::
|
||||
|
||||
cdc.exe
|
||||
|
||||
This will compile the library to a file called ``libdyaml.a`` on Unix/Linux or
|
||||
``libdyaml.lib`` on Windows.
|
||||
|
||||
|
||||
-------------------------
|
||||
Your first D:YAML project
|
||||
-------------------------
|
||||
|
||||
Create a directory for your project and in that directory, create a file called
|
||||
``input.yaml`` with the following contents:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Hello World :
|
||||
- Hello
|
||||
- World
|
||||
Answer: 42
|
||||
|
||||
This will serve as input for our example.
|
||||
|
||||
Now we need to parse it. Create a file called "main.d". Paste following code
|
||||
into the file:
|
||||
|
||||
.. code-block:: d
|
||||
|
||||
import std.stdio;
|
||||
import yaml;
|
||||
|
||||
void main()
|
||||
{
|
||||
yaml.Node root = yaml.load("input.yaml");
|
||||
foreach(string word; root["Hello World"])
|
||||
{
|
||||
writeln(word);
|
||||
}
|
||||
writeln("The answer is ", root["Answer"].get!int);
|
||||
}
|
||||
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Explanation of the code
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
First, we import the *yaml* module. This is the only module you need to import
|
||||
to use D:YAML - it automatically imports all needed modules.
|
||||
|
||||
Next we load the file using the *yaml.load()* function - this loads the file as
|
||||
**one** YAML document and throws *YAMLException*, D:YAML exception type, if the
|
||||
file could not be parsed or does not contain exactly one document. Note that we
|
||||
don't do any error checking here in order to keep the example as simple as
|
||||
possible.
|
||||
|
||||
*yaml.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 first, as it is a sequence, and use the
|
||||
*yaml.Node.get()* method on the second to get its value as an integer.
|
||||
|
||||
You can iterate over a mapping or sequence as if it was an associative or normal
|
||||
array. If you try to iterate over a scalar, it will throw a *YAMLException*.
|
||||
|
||||
You can iterate over subnodes using yaml.Node as the iterated type, or specify
|
||||
the type subnodes are expected to have. D:YAML will automatically convert
|
||||
iterated subnodes 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 *yaml.Node.get()* method is used to get value of a scalar node as specified
|
||||
type. D:YAML will try to return the scalar as specified type, converting if
|
||||
needed, throwing *YAMLException* if not possible.
|
||||
|
||||
|
||||
^^^^^^^^^
|
||||
Compiling
|
||||
^^^^^^^^^
|
||||
|
||||
To compile your project, you must give DMD the directories containing import
|
||||
modules and the library. You also need to tell it to link with D:YAML. The import
|
||||
directory should be the D:YAML package directory. You can specify it using the
|
||||
``-I`` option of DMD. The library directory should point to where you put the
|
||||
compiled D:YAML library. On Unix/Linux you can specify it using the ``-L-L``
|
||||
option, and link with D:YAML using the ``-L-l`` option. On Windows, the import
|
||||
directory is used as the library directory. To link with the library on Windows,
|
||||
just add the path to it relative to the current directory.
|
||||
|
||||
For example, if you extracted D:YAML to ``/home/xxx/dyaml`` and compiled it in
|
||||
that directory, your project is in ``/home/xxx/dyaml-project``, and you are
|
||||
currently in that directory, you can compile the project with the following
|
||||
command on Unix/Linux::
|
||||
|
||||
dmd -I../dyaml -L-L../dyaml -L-ldyaml main.d
|
||||
|
||||
And the following on Windows::
|
||||
|
||||
dmd -I../dyaml ../dyaml/libdyaml.lib main.d
|
||||
|
||||
This will produce an executable called ``main`` or ``main.exe`` in your
|
||||
directory. When you run it, it should produce the following output::
|
||||
|
||||
Hello
|
||||
World
|
||||
The answer is 42
|
||||
|
||||
|
||||
^^^^^^^^^^
|
||||
Conclusion
|
||||
^^^^^^^^^^
|
||||
|
||||
You should now have a basic idea about how to use D:YAML. To learn more, look at
|
||||
the `API documentation <../api/index.html>`_ and other tutorials. You can find code for this
|
||||
example in the ``example/getting_started`` directory in the package.
|
273
doc/html/_sources/tutorials/yaml_syntax.txt
Normal file
|
@ -0,0 +1,273 @@
|
|||
===========
|
||||
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 to be as human readable as
|
||||
possible. 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, YAML 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 either depends 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 ``...`` . If there is only one document, ``---`` can be
|
||||
left out.
|
||||
|
||||
Single document with no explicit start or end:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
|
||||
Same document with explicit start and end:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
...
|
||||
|
||||
A stream containing multiple documents:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
- 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.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Block context
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Flow context
|
||||
[Red, Green, Blue]
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Nested
|
||||
-
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
-
|
||||
- Linux
|
||||
- BSD
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Nested flow
|
||||
[[Red, Green, Blue], [Linux, BSD]]
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#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:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Block context
|
||||
CPU: Athlon
|
||||
GPU: Radeon
|
||||
OS: Linux
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Flow context
|
||||
{CPU: Athlon, GPU: Radeon, OS: Linux}
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Nested
|
||||
PC:
|
||||
CPU: Athlon
|
||||
GPU: Radeon
|
||||
OS: Debian
|
||||
Phone:
|
||||
CPU: Cortex
|
||||
GPU: PowerVR
|
||||
OS: Android
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Nested flow
|
||||
{PC: {CPU: Athlon, GPU: Radeon, OS: Debian},
|
||||
Phone: {CPU: Cortex, GPU: PowerVR, OS: Android}}
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Nested in a sequence
|
||||
- CPU: Athlon
|
||||
GPU: Radeon
|
||||
OS: Debian
|
||||
- CPU: Cortex
|
||||
GPU: PowerVR
|
||||
OS: Android
|
||||
|
||||
Complex keys start with question mark+space "? ".
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#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:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
scalar: Plain scalar
|
||||
|
||||
Single quoted scalars start and end with single quotes. A single quote is
|
||||
represented by a pair of single quotes ''.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
scalar: 'Single quoted scalar ending with some spaces '
|
||||
|
||||
Double quoted scalars support C-style escape sequences.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
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.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
scalar: |
|
||||
Newlines are preserved
|
||||
First line
|
||||
Second line
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
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).
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
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:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
answer: !!int "42"
|
||||
name: !!str "Arthur Dent"
|
||||
|
||||
Implicit tags:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
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 yaml.YAMLNull
|
||||
!!bool bool
|
||||
!!int long
|
||||
!!float real
|
||||
!!binary ubyte[]
|
||||
!!timestamp datetime.SysTime
|
||||
!!map, !!omap, !!pairs Node.Pair[]
|
||||
!!seq, !!set Node[]
|
||||
!!str string
|
||||
====================== ================
|
509
doc/html/_static/basic.css
Normal file
|
@ -0,0 +1,509 @@
|
|||
/*
|
||||
* basic.css
|
||||
* ~~~~~~~~~
|
||||
*
|
||||
* Sphinx stylesheet -- basic theme.
|
||||
*
|
||||
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/* -- main layout ----------------------------------------------------------- */
|
||||
|
||||
div.clearer {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* -- relbar ---------------------------------------------------------------- */
|
||||
|
||||
div.related {
|
||||
width: 100%;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
div.related h3 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.related ul {
|
||||
margin: 0;
|
||||
padding: 0 0 0 10px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
div.related li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.related li.right {
|
||||
float: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
/* -- sidebar --------------------------------------------------------------- */
|
||||
|
||||
div.sphinxsidebarwrapper {
|
||||
padding: 10px 5px 0 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
float: left;
|
||||
width: 230px;
|
||||
margin-left: -100%;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul,
|
||||
div.sphinxsidebar ul.want-points {
|
||||
margin-left: 20px;
|
||||
list-style: square;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar form {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input {
|
||||
border: 1px solid #98dbcc;
|
||||
font-family: sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* -- search page ----------------------------------------------------------- */
|
||||
|
||||
ul.search {
|
||||
margin: 10px 0 0 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.search li {
|
||||
padding: 5px 0 5px 20px;
|
||||
background-image: url(file.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 7px;
|
||||
}
|
||||
|
||||
ul.search li a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ul.search li div.context {
|
||||
color: #888;
|
||||
margin: 2px 0 0 30px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
ul.keywordmatches li.goodmatch a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* -- index page ------------------------------------------------------------ */
|
||||
|
||||
table.contentstable {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
table.contentstable p.biglink {
|
||||
line-height: 150%;
|
||||
}
|
||||
|
||||
a.biglink {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
span.linkdescr {
|
||||
font-style: italic;
|
||||
padding-top: 5px;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
/* -- general index --------------------------------------------------------- */
|
||||
|
||||
table.indextable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table.indextable td {
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.indextable dl, table.indextable dd {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
table.indextable tr.pcap {
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
table.indextable tr.cap {
|
||||
margin-top: 10px;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
img.toggler {
|
||||
margin-right: 3px;
|
||||
margin-top: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.modindex-jumpbox {
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
margin: 1em 0 1em 0;
|
||||
padding: 0.4em;
|
||||
}
|
||||
|
||||
div.genindex-jumpbox {
|
||||
border-top: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
margin: 1em 0 1em 0;
|
||||
padding: 0.4em;
|
||||
}
|
||||
|
||||
/* -- general body styles --------------------------------------------------- */
|
||||
|
||||
a.headerlink {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
h1:hover > a.headerlink,
|
||||
h2:hover > a.headerlink,
|
||||
h3:hover > a.headerlink,
|
||||
h4:hover > a.headerlink,
|
||||
h5:hover > a.headerlink,
|
||||
h6:hover > a.headerlink,
|
||||
dt:hover > a.headerlink {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
div.body p.caption {
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
div.body td {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.field-list ul {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.first {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
p.rubric {
|
||||
margin-top: 30px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.align-center {
|
||||
clear: both;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* -- sidebars -------------------------------------------------------------- */
|
||||
|
||||
div.sidebar {
|
||||
margin: 0 0 0.5em 1em;
|
||||
border: 1px solid #ddb;
|
||||
padding: 7px 7px 0 7px;
|
||||
background-color: #ffe;
|
||||
width: 40%;
|
||||
float: right;
|
||||
}
|
||||
|
||||
p.sidebar-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* -- topics ---------------------------------------------------------------- */
|
||||
|
||||
div.topic {
|
||||
border: 1px solid #ccc;
|
||||
padding: 7px 7px 0 7px;
|
||||
margin: 10px 0 10px 0;
|
||||
}
|
||||
|
||||
p.topic-title {
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* -- admonitions ----------------------------------------------------------- */
|
||||
|
||||
div.admonition {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
div.admonition dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.admonition dl {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
p.admonition-title {
|
||||
margin: 0px 10px 5px 0px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.body p.centered {
|
||||
text-align: center;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
/* -- tables ---------------------------------------------------------------- */
|
||||
|
||||
table.docutils {
|
||||
border: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table.docutils td, table.docutils th {
|
||||
padding: 1px 8px 1px 5px;
|
||||
border-top: 0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
|
||||
table.field-list td, table.field-list th {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
table.footnote td, table.footnote th {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
table.citation td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* -- other body styles ----------------------------------------------------- */
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha;
|
||||
}
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha;
|
||||
}
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman;
|
||||
}
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
dd p {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
dd ul, dd table {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-top: 3px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
dt:target, .highlighted {
|
||||
background-color: #fbe54e;
|
||||
}
|
||||
|
||||
dl.glossary dt {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.field-list ul {
|
||||
margin: 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.field-list p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.refcount {
|
||||
color: #060;
|
||||
}
|
||||
|
||||
.optional {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.versionmodified {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.system-message {
|
||||
background-color: #fda;
|
||||
padding: 5px;
|
||||
border: 3px solid red;
|
||||
}
|
||||
|
||||
.footnote:target {
|
||||
background-color: #ffa
|
||||
}
|
||||
|
||||
.line-block {
|
||||
display: block;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.line-block .line-block {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
|
||||
.guilabel, .menuselection {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.accelerator {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.classifier {
|
||||
font-style: oblique;
|
||||
}
|
||||
|
||||
/* -- code displays --------------------------------------------------------- */
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
td.linenos pre {
|
||||
padding: 5px 0px;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
table.highlighttable {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
table.highlighttable td {
|
||||
padding: 0 0.5em 0 0.5em;
|
||||
}
|
||||
|
||||
tt.descname {
|
||||
background-color: transparent;
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
tt.descclassname {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
tt.xref, a tt {
|
||||
background-color: transparent;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.viewcode-link {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.viewcode-back {
|
||||
float: right;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
div.viewcode-block:target {
|
||||
margin: -1px -10px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
/* -- math display ---------------------------------------------------------- */
|
||||
|
||||
img.math {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.body div.math p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
span.eqno {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* -- printout stylesheet --------------------------------------------------- */
|
||||
|
||||
@media print {
|
||||
div.document,
|
||||
div.documentwrapper,
|
||||
div.bodywrapper {
|
||||
margin: 0 !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.sphinxsidebar,
|
||||
div.related,
|
||||
div.footer,
|
||||
#top-link {
|
||||
display: none;
|
||||
}
|
||||
}
|
255
doc/html/_static/default.css
Normal file
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* default.css_t
|
||||
* ~~~~~~~~~~~~~
|
||||
*
|
||||
* Sphinx stylesheet -- default theme.
|
||||
*
|
||||
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
@import url("basic.css");
|
||||
|
||||
/* -- page layout ----------------------------------------------------------- */
|
||||
|
||||
body {
|
||||
font-family: Verdana, "Deja Vu", "Bitstream Vera Sans", sans-serif;
|
||||
font-size: 100%;
|
||||
background-color: #1f252b;
|
||||
color: #000;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.document {
|
||||
background-color: #1f252b;
|
||||
}
|
||||
|
||||
div.documentwrapper {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.bodywrapper {
|
||||
margin: 0 0 0 230px;
|
||||
}
|
||||
|
||||
div.body {
|
||||
background-color: #f6f6f6;
|
||||
color: black;
|
||||
padding: 0 20px 30px 20px;
|
||||
}
|
||||
|
||||
div.footer {
|
||||
color: #ccc;
|
||||
width: 100%;
|
||||
padding: 9px 0 9px 0;
|
||||
text-align: center;
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
div.footer a {
|
||||
color: #ccc;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
div.related {
|
||||
background-color: #303333;
|
||||
line-height: 30px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
div.related a {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3 {
|
||||
font-family: Georgia, "Times New Roman", Times, serif;
|
||||
color: #ffffff;
|
||||
font-size: 1.4em;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3 a {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h4 {
|
||||
font-family: Georgia, "Times New Roman", Times, serif;
|
||||
color: #ffffff;
|
||||
font-size: 1.3em;
|
||||
font-weight: normal;
|
||||
margin: 5px 0 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar p {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
div.sphinxsidebar p.topless {
|
||||
margin: 5px 10px 10px 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul {
|
||||
margin: 10px;
|
||||
padding: 0;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
div.sphinxsidebar a {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input {
|
||||
border: 1px solid #ddd;
|
||||
font-family: sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
|
||||
/* -- hyperlink styles ------------------------------------------------------ */
|
||||
|
||||
a {
|
||||
color: #006;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #606;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -- body styles ----------------------------------------------------------- */
|
||||
|
||||
div.body h1,
|
||||
div.body h2,
|
||||
div.body h3,
|
||||
div.body h4,
|
||||
div.body h5,
|
||||
div.body h6 {
|
||||
font-family: Georgia, "Times New Roman", Times, serif;
|
||||
background-color: #f6f6f6;
|
||||
font-weight: normal;
|
||||
color: #633;
|
||||
border-bottom: 1px solid #ccc;
|
||||
margin: 20px -20px 10px -20px;
|
||||
padding: 3px 0 3px 10px;
|
||||
}
|
||||
|
||||
div.body h1 { margin-top: 0; font-size: 200%; }
|
||||
div.body h2 { font-size: 160%; }
|
||||
div.body h3 { font-size: 140%; }
|
||||
div.body h4 { font-size: 120%; }
|
||||
div.body h5 { font-size: 110%; }
|
||||
div.body h6 { font-size: 100%; }
|
||||
|
||||
a.headerlink {
|
||||
color: #006;
|
||||
font-size: 0.8em;
|
||||
padding: 0 4px 0 4px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.headerlink:hover {
|
||||
background-color: #006;
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.body p, div.body dd, div.body li {
|
||||
text-align: justify;
|
||||
line-height: 130%;
|
||||
}
|
||||
|
||||
div.admonition p.admonition-title + p {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.admonition p {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
div.admonition pre {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
div.admonition ul, div.admonition ol {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
div.note {
|
||||
background-color: #eee;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div.seealso {
|
||||
background-color: #ffc;
|
||||
border: 1px solid #ff6;
|
||||
}
|
||||
|
||||
div.topic {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
div.warning {
|
||||
background-color: #ffe4e4;
|
||||
border: 1px solid #f66;
|
||||
}
|
||||
|
||||
p.admonition-title {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
p.admonition-title:after {
|
||||
content: ":";
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 5px;
|
||||
background-color: fcfcfc;
|
||||
color: 000066;
|
||||
line-height: 120%;
|
||||
border: 1px solid #ac9;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
tt {
|
||||
background-color: #ecf0f3;
|
||||
padding: 0 1px 0 1px;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #ede;
|
||||
}
|
||||
|
||||
.warning tt {
|
||||
background: #efc2c2;
|
||||
}
|
||||
|
||||
.note tt {
|
||||
background: #d6d6d6;
|
||||
}
|
||||
|
||||
.viewcode-back {
|
||||
font-family: Verdana, "Deja Vu", "Bitstream Vera Sans", sans-serif;
|
||||
}
|
||||
|
||||
div.viewcode-block:target {
|
||||
background-color: #f4debf;
|
||||
border-top: 1px solid #ac9;
|
||||
border-bottom: 1px solid #ac9;
|
||||
}
|
247
doc/html/_static/doctools.js
Normal file
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* doctools.js
|
||||
* ~~~~~~~~~~~
|
||||
*
|
||||
* Sphinx JavaScript utilties for all documentation.
|
||||
*
|
||||
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* select a different prefix for underscore
|
||||
*/
|
||||
$u = _.noConflict();
|
||||
|
||||
/**
|
||||
* make the code below compatible with browsers without
|
||||
* an installed firebug like debugger
|
||||
if (!window.console || !console.firebug) {
|
||||
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
|
||||
"dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
|
||||
"profile", "profileEnd"];
|
||||
window.console = {};
|
||||
for (var i = 0; i < names.length; ++i)
|
||||
window.console[names[i]] = function() {};
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* small helper function to urldecode strings
|
||||
*/
|
||||
jQuery.urldecode = function(x) {
|
||||
return decodeURIComponent(x).replace(/\+/g, ' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* small helper function to urlencode strings
|
||||
*/
|
||||
jQuery.urlencode = encodeURIComponent;
|
||||
|
||||
/**
|
||||
* This function returns the parsed url parameters of the
|
||||
* current request. Multiple values per key are supported,
|
||||
* it will always return arrays of strings for the value parts.
|
||||
*/
|
||||
jQuery.getQueryParameters = function(s) {
|
||||
if (typeof s == 'undefined')
|
||||
s = document.location.search;
|
||||
var parts = s.substr(s.indexOf('?') + 1).split('&');
|
||||
var result = {};
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
var tmp = parts[i].split('=', 2);
|
||||
var key = jQuery.urldecode(tmp[0]);
|
||||
var value = jQuery.urldecode(tmp[1]);
|
||||
if (key in result)
|
||||
result[key].push(value);
|
||||
else
|
||||
result[key] = [value];
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* small function to check if an array contains
|
||||
* a given item.
|
||||
*/
|
||||
jQuery.contains = function(arr, item) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (arr[i] == item)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* highlight a given string on a jquery object by wrapping it in
|
||||
* span elements with the given class name.
|
||||
*/
|
||||
jQuery.fn.highlightText = function(text, className) {
|
||||
function highlight(node) {
|
||||
if (node.nodeType == 3) {
|
||||
var val = node.nodeValue;
|
||||
var pos = val.toLowerCase().indexOf(text);
|
||||
if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
|
||||
var span = document.createElement("span");
|
||||
span.className = className;
|
||||
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
|
||||
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
|
||||
document.createTextNode(val.substr(pos + text.length)),
|
||||
node.nextSibling));
|
||||
node.nodeValue = val.substr(0, pos);
|
||||
}
|
||||
}
|
||||
else if (!jQuery(node).is("button, select, textarea")) {
|
||||
jQuery.each(node.childNodes, function() {
|
||||
highlight(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
return this.each(function() {
|
||||
highlight(this);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Small JavaScript module for the documentation.
|
||||
*/
|
||||
var Documentation = {
|
||||
|
||||
init : function() {
|
||||
this.fixFirefoxAnchorBug();
|
||||
this.highlightSearchWords();
|
||||
this.initIndexTable();
|
||||
},
|
||||
|
||||
/**
|
||||
* i18n support
|
||||
*/
|
||||
TRANSLATIONS : {},
|
||||
PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
|
||||
LOCALE : 'unknown',
|
||||
|
||||
// gettext and ngettext don't access this so that the functions
|
||||
// can safely bound to a different name (_ = Documentation.gettext)
|
||||
gettext : function(string) {
|
||||
var translated = Documentation.TRANSLATIONS[string];
|
||||
if (typeof translated == 'undefined')
|
||||
return string;
|
||||
return (typeof translated == 'string') ? translated : translated[0];
|
||||
},
|
||||
|
||||
ngettext : function(singular, plural, n) {
|
||||
var translated = Documentation.TRANSLATIONS[singular];
|
||||
if (typeof translated == 'undefined')
|
||||
return (n == 1) ? singular : plural;
|
||||
return translated[Documentation.PLURALEXPR(n)];
|
||||
},
|
||||
|
||||
addTranslations : function(catalog) {
|
||||
for (var key in catalog.messages)
|
||||
this.TRANSLATIONS[key] = catalog.messages[key];
|
||||
this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
|
||||
this.LOCALE = catalog.locale;
|
||||
},
|
||||
|
||||
/**
|
||||
* add context elements like header anchor links
|
||||
*/
|
||||
addContextElements : function() {
|
||||
$('div[id] > :header:first').each(function() {
|
||||
$('<a class="headerlink">\u00B6</a>').
|
||||
attr('href', '#' + this.id).
|
||||
attr('title', _('Permalink to this headline')).
|
||||
appendTo(this);
|
||||
});
|
||||
$('dt[id]').each(function() {
|
||||
$('<a class="headerlink">\u00B6</a>').
|
||||
attr('href', '#' + this.id).
|
||||
attr('title', _('Permalink to this definition')).
|
||||
appendTo(this);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* workaround a firefox stupidity
|
||||
*/
|
||||
fixFirefoxAnchorBug : function() {
|
||||
if (document.location.hash && $.browser.mozilla)
|
||||
window.setTimeout(function() {
|
||||
document.location.href += '';
|
||||
}, 10);
|
||||
},
|
||||
|
||||
/**
|
||||
* highlight the search words provided in the url in the text
|
||||
*/
|
||||
highlightSearchWords : function() {
|
||||
var params = $.getQueryParameters();
|
||||
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
|
||||
if (terms.length) {
|
||||
var body = $('div.body');
|
||||
window.setTimeout(function() {
|
||||
$.each(terms, function() {
|
||||
body.highlightText(this.toLowerCase(), 'highlighted');
|
||||
});
|
||||
}, 10);
|
||||
$('<li class="highlight-link"><a href="javascript:Documentation.' +
|
||||
'hideSearchWords()">' + _('Hide Search Matches') + '</a></li>')
|
||||
.appendTo($('.sidebar .this-page-menu'));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* init the domain index toggle buttons
|
||||
*/
|
||||
initIndexTable : function() {
|
||||
var togglers = $('img.toggler').click(function() {
|
||||
var src = $(this).attr('src');
|
||||
var idnum = $(this).attr('id').substr(7);
|
||||
$('tr.cg-' + idnum).toggle();
|
||||
if (src.substr(-9) == 'minus.png')
|
||||
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
|
||||
else
|
||||
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
|
||||
}).css('display', '');
|
||||
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
|
||||
togglers.click();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* helper function to hide the search marks again
|
||||
*/
|
||||
hideSearchWords : function() {
|
||||
$('.sidebar .this-page-menu li.highlight-link').fadeOut(300);
|
||||
$('span.highlighted').removeClass('highlighted');
|
||||
},
|
||||
|
||||
/**
|
||||
* make the url absolute
|
||||
*/
|
||||
makeURL : function(relativeURL) {
|
||||
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
|
||||
},
|
||||
|
||||
/**
|
||||
* get the current relative url
|
||||
*/
|
||||
getCurrentURL : function() {
|
||||
var path = document.location.pathname;
|
||||
var parts = path.split(/\//);
|
||||
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
|
||||
if (this == '..')
|
||||
parts.pop();
|
||||
});
|
||||
var url = parts.join('/');
|
||||
return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
|
||||
}
|
||||
};
|
||||
|
||||
// quick alias for translations
|
||||
_ = Documentation.gettext;
|
||||
|
||||
$(document).ready(function() {
|
||||
Documentation.init();
|
||||
});
|
BIN
doc/html/_static/file.png
Normal file
After Width: | Height: | Size: 392 B |
8176
doc/html/_static/jquery.js
vendored
Normal file
BIN
doc/html/_static/logo210.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
doc/html/_static/minus.png
Normal file
After Width: | Height: | Size: 199 B |
BIN
doc/html/_static/plus.png
Normal file
After Width: | Height: | Size: 199 B |
61
doc/html/_static/pygments.css
Normal file
|
@ -0,0 +1,61 @@
|
|||
.hll { background-color: #ffffcc }
|
||||
.c { color: #408090; font-style: italic } /* Comment */
|
||||
.err { border: 1px solid #FF0000 } /* Error */
|
||||
.k { color: #007020; font-weight: bold } /* Keyword */
|
||||
.o { color: #666666 } /* Operator */
|
||||
.cm { color: #408090; font-style: italic } /* Comment.Multiline */
|
||||
.cp { color: #007020 } /* Comment.Preproc */
|
||||
.c1 { color: #408090; font-style: italic } /* Comment.Single */
|
||||
.cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
|
||||
.gd { color: #A00000 } /* Generic.Deleted */
|
||||
.ge { font-style: italic } /* Generic.Emph */
|
||||
.gr { color: #FF0000 } /* Generic.Error */
|
||||
.gh { color: #000080; font-weight: bold } /* Generic.Heading */
|
||||
.gi { color: #00A000 } /* Generic.Inserted */
|
||||
.go { color: #303030 } /* Generic.Output */
|
||||
.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
|
||||
.gs { font-weight: bold } /* Generic.Strong */
|
||||
.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
|
||||
.gt { color: #0040D0 } /* Generic.Traceback */
|
||||
.kc { color: #007020; font-weight: bold } /* Keyword.Constant */
|
||||
.kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
|
||||
.kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
|
||||
.kp { color: #007020 } /* Keyword.Pseudo */
|
||||
.kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
|
||||
.kt { color: #902000 } /* Keyword.Type */
|
||||
.m { color: #208050 } /* Literal.Number */
|
||||
.s { color: #4070a0 } /* Literal.String */
|
||||
.na { color: #4070a0 } /* Name.Attribute */
|
||||
.nb { color: #007020 } /* Name.Builtin */
|
||||
.nc { color: #0e84b5; font-weight: bold } /* Name.Class */
|
||||
.no { color: #60add5 } /* Name.Constant */
|
||||
.nd { color: #555555; font-weight: bold } /* Name.Decorator */
|
||||
.ni { color: #d55537; font-weight: bold } /* Name.Entity */
|
||||
.ne { color: #007020 } /* Name.Exception */
|
||||
.nf { color: #06287e } /* Name.Function */
|
||||
.nl { color: #002070; font-weight: bold } /* Name.Label */
|
||||
.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
|
||||
.nt { color: #062873; font-weight: bold } /* Name.Tag */
|
||||
.nv { color: #bb60d5 } /* Name.Variable */
|
||||
.ow { color: #007020; font-weight: bold } /* Operator.Word */
|
||||
.w { color: #bbbbbb } /* Text.Whitespace */
|
||||
.mf { color: #208050 } /* Literal.Number.Float */
|
||||
.mh { color: #208050 } /* Literal.Number.Hex */
|
||||
.mi { color: #208050 } /* Literal.Number.Integer */
|
||||
.mo { color: #208050 } /* Literal.Number.Oct */
|
||||
.sb { color: #4070a0 } /* Literal.String.Backtick */
|
||||
.sc { color: #4070a0 } /* Literal.String.Char */
|
||||
.sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
|
||||
.s2 { color: #4070a0 } /* Literal.String.Double */
|
||||
.se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
|
||||
.sh { color: #4070a0 } /* Literal.String.Heredoc */
|
||||
.si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
|
||||
.sx { color: #c65d09 } /* Literal.String.Other */
|
||||
.sr { color: #235388 } /* Literal.String.Regex */
|
||||
.s1 { color: #4070a0 } /* Literal.String.Single */
|
||||
.ss { color: #517918 } /* Literal.String.Symbol */
|
||||
.bp { color: #007020 } /* Name.Builtin.Pseudo */
|
||||
.vc { color: #bb60d5 } /* Name.Variable.Class */
|
||||
.vg { color: #bb60d5 } /* Name.Variable.Global */
|
||||
.vi { color: #bb60d5 } /* Name.Variable.Instance */
|
||||
.il { color: #208050 } /* Literal.Number.Integer.Long */
|
518
doc/html/_static/searchtools.js
Normal file
|
@ -0,0 +1,518 @@
|
|||
/*
|
||||
* searchtools.js
|
||||
* ~~~~~~~~~~~~~~
|
||||
*
|
||||
* Sphinx JavaScript utilties for the full-text search.
|
||||
*
|
||||
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* helper function to return a node containing the
|
||||
* search summary for a given text. keywords is a list
|
||||
* of stemmed words, hlwords is the list of normal, unstemmed
|
||||
* words. the first one is used to find the occurance, the
|
||||
* latter for highlighting it.
|
||||
*/
|
||||
|
||||
jQuery.makeSearchSummary = function(text, keywords, hlwords) {
|
||||
var textLower = text.toLowerCase();
|
||||
var start = 0;
|
||||
$.each(keywords, function() {
|
||||
var i = textLower.indexOf(this.toLowerCase());
|
||||
if (i > -1)
|
||||
start = i;
|
||||
});
|
||||
start = Math.max(start - 120, 0);
|
||||
var excerpt = ((start > 0) ? '...' : '') +
|
||||
$.trim(text.substr(start, 240)) +
|
||||
((start + 240 - text.length) ? '...' : '');
|
||||
var rv = $('<div class="context"></div>').text(excerpt);
|
||||
$.each(hlwords, function() {
|
||||
rv = rv.highlightText(this, 'highlighted');
|
||||
});
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Porter Stemmer
|
||||
*/
|
||||
var PorterStemmer = function() {
|
||||
|
||||
var step2list = {
|
||||
ational: 'ate',
|
||||
tional: 'tion',
|
||||
enci: 'ence',
|
||||
anci: 'ance',
|
||||
izer: 'ize',
|
||||
bli: 'ble',
|
||||
alli: 'al',
|
||||
entli: 'ent',
|
||||
eli: 'e',
|
||||
ousli: 'ous',
|
||||
ization: 'ize',
|
||||
ation: 'ate',
|
||||
ator: 'ate',
|
||||
alism: 'al',
|
||||
iveness: 'ive',
|
||||
fulness: 'ful',
|
||||
ousness: 'ous',
|
||||
aliti: 'al',
|
||||
iviti: 'ive',
|
||||
biliti: 'ble',
|
||||
logi: 'log'
|
||||
};
|
||||
|
||||
var step3list = {
|
||||
icate: 'ic',
|
||||
ative: '',
|
||||
alize: 'al',
|
||||
iciti: 'ic',
|
||||
ical: 'ic',
|
||||
ful: '',
|
||||
ness: ''
|
||||
};
|
||||
|
||||
var c = "[^aeiou]"; // consonant
|
||||
var v = "[aeiouy]"; // vowel
|
||||
var C = c + "[^aeiouy]*"; // consonant sequence
|
||||
var V = v + "[aeiou]*"; // vowel sequence
|
||||
|
||||
var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
|
||||
var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
|
||||
var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
|
||||
var s_v = "^(" + C + ")?" + v; // vowel in stem
|
||||
|
||||
this.stemWord = function (w) {
|
||||
var stem;
|
||||
var suffix;
|
||||
var firstch;
|
||||
var origword = w;
|
||||
|
||||
if (w.length < 3)
|
||||
return w;
|
||||
|
||||
var re;
|
||||
var re2;
|
||||
var re3;
|
||||
var re4;
|
||||
|
||||
firstch = w.substr(0,1);
|
||||
if (firstch == "y")
|
||||
w = firstch.toUpperCase() + w.substr(1);
|
||||
|
||||
// Step 1a
|
||||
re = /^(.+?)(ss|i)es$/;
|
||||
re2 = /^(.+?)([^s])s$/;
|
||||
|
||||
if (re.test(w))
|
||||
w = w.replace(re,"$1$2");
|
||||
else if (re2.test(w))
|
||||
w = w.replace(re2,"$1$2");
|
||||
|
||||
// Step 1b
|
||||
re = /^(.+?)eed$/;
|
||||
re2 = /^(.+?)(ed|ing)$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
re = new RegExp(mgr0);
|
||||
if (re.test(fp[1])) {
|
||||
re = /.$/;
|
||||
w = w.replace(re,"");
|
||||
}
|
||||
}
|
||||
else if (re2.test(w)) {
|
||||
var fp = re2.exec(w);
|
||||
stem = fp[1];
|
||||
re2 = new RegExp(s_v);
|
||||
if (re2.test(stem)) {
|
||||
w = stem;
|
||||
re2 = /(at|bl|iz)$/;
|
||||
re3 = new RegExp("([^aeiouylsz])\\1$");
|
||||
re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
|
||||
if (re2.test(w))
|
||||
w = w + "e";
|
||||
else if (re3.test(w)) {
|
||||
re = /.$/;
|
||||
w = w.replace(re,"");
|
||||
}
|
||||
else if (re4.test(w))
|
||||
w = w + "e";
|
||||
}
|
||||
}
|
||||
|
||||
// Step 1c
|
||||
re = /^(.+?)y$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
stem = fp[1];
|
||||
re = new RegExp(s_v);
|
||||
if (re.test(stem))
|
||||
w = stem + "i";
|
||||
}
|
||||
|
||||
// Step 2
|
||||
re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
stem = fp[1];
|
||||
suffix = fp[2];
|
||||
re = new RegExp(mgr0);
|
||||
if (re.test(stem))
|
||||
w = stem + step2list[suffix];
|
||||
}
|
||||
|
||||
// Step 3
|
||||
re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
stem = fp[1];
|
||||
suffix = fp[2];
|
||||
re = new RegExp(mgr0);
|
||||
if (re.test(stem))
|
||||
w = stem + step3list[suffix];
|
||||
}
|
||||
|
||||
// Step 4
|
||||
re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
|
||||
re2 = /^(.+?)(s|t)(ion)$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
stem = fp[1];
|
||||
re = new RegExp(mgr1);
|
||||
if (re.test(stem))
|
||||
w = stem;
|
||||
}
|
||||
else if (re2.test(w)) {
|
||||
var fp = re2.exec(w);
|
||||
stem = fp[1] + fp[2];
|
||||
re2 = new RegExp(mgr1);
|
||||
if (re2.test(stem))
|
||||
w = stem;
|
||||
}
|
||||
|
||||
// Step 5
|
||||
re = /^(.+?)e$/;
|
||||
if (re.test(w)) {
|
||||
var fp = re.exec(w);
|
||||
stem = fp[1];
|
||||
re = new RegExp(mgr1);
|
||||
re2 = new RegExp(meq1);
|
||||
re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
|
||||
if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
|
||||
w = stem;
|
||||
}
|
||||
re = /ll$/;
|
||||
re2 = new RegExp(mgr1);
|
||||
if (re.test(w) && re2.test(w)) {
|
||||
re = /.$/;
|
||||
w = w.replace(re,"");
|
||||
}
|
||||
|
||||
// and turn initial Y back to y
|
||||
if (firstch == "y")
|
||||
w = firstch.toLowerCase() + w.substr(1);
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Search Module
|
||||
*/
|
||||
var Search = {
|
||||
|
||||
_index : null,
|
||||
_queued_query : null,
|
||||
_pulse_status : -1,
|
||||
|
||||
init : function() {
|
||||
var params = $.getQueryParameters();
|
||||
if (params.q) {
|
||||
var query = params.q[0];
|
||||
$('input[name="q"]')[0].value = query;
|
||||
this.performSearch(query);
|
||||
}
|
||||
},
|
||||
|
||||
loadIndex : function(url) {
|
||||
$.ajax({type: "GET", url: url, data: null, success: null,
|
||||
dataType: "script", cache: true});
|
||||
},
|
||||
|
||||
setIndex : function(index) {
|
||||
var q;
|
||||
this._index = index;
|
||||
if ((q = this._queued_query) !== null) {
|
||||
this._queued_query = null;
|
||||
Search.query(q);
|
||||
}
|
||||
},
|
||||
|
||||
hasIndex : function() {
|
||||
return this._index !== null;
|
||||
},
|
||||
|
||||
deferQuery : function(query) {
|
||||
this._queued_query = query;
|
||||
},
|
||||
|
||||
stopPulse : function() {
|
||||
this._pulse_status = 0;
|
||||
},
|
||||
|
||||
startPulse : function() {
|
||||
if (this._pulse_status >= 0)
|
||||
return;
|
||||
function pulse() {
|
||||
Search._pulse_status = (Search._pulse_status + 1) % 4;
|
||||
var dotString = '';
|
||||
for (var i = 0; i < Search._pulse_status; i++)
|
||||
dotString += '.';
|
||||
Search.dots.text(dotString);
|
||||
if (Search._pulse_status > -1)
|
||||
window.setTimeout(pulse, 500);
|
||||
};
|
||||
pulse();
|
||||
},
|
||||
|
||||
/**
|
||||
* perform a search for something
|
||||
*/
|
||||
performSearch : function(query) {
|
||||
// create the required interface elements
|
||||
this.out = $('#search-results');
|
||||
this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
|
||||
this.dots = $('<span></span>').appendTo(this.title);
|
||||
this.status = $('<p style="display: none"></p>').appendTo(this.out);
|
||||
this.output = $('<ul class="search"/>').appendTo(this.out);
|
||||
|
||||
$('#search-progress').text(_('Preparing search...'));
|
||||
this.startPulse();
|
||||
|
||||
// index already loaded, the browser was quick!
|
||||
if (this.hasIndex())
|
||||
this.query(query);
|
||||
else
|
||||
this.deferQuery(query);
|
||||
},
|
||||
|
||||
query : function(query) {
|
||||
var stopwords = ['and', 'then', 'into', 'it', 'as', 'are', 'in',
|
||||
'if', 'for', 'no', 'there', 'their', 'was', 'is',
|
||||
'be', 'to', 'that', 'but', 'they', 'not', 'such',
|
||||
'with', 'by', 'a', 'on', 'these', 'of', 'will',
|
||||
'this', 'near', 'the', 'or', 'at'];
|
||||
|
||||
// stem the searchterms and add them to the correct list
|
||||
var stemmer = new PorterStemmer();
|
||||
var searchterms = [];
|
||||
var excluded = [];
|
||||
var hlterms = [];
|
||||
var tmp = query.split(/\s+/);
|
||||
var object = (tmp.length == 1) ? tmp[0].toLowerCase() : null;
|
||||
for (var i = 0; i < tmp.length; i++) {
|
||||
if ($u.indexOf(stopwords, tmp[i]) != -1 || tmp[i].match(/^\d+$/) ||
|
||||
tmp[i] == "") {
|
||||
// skip this "word"
|
||||
continue;
|
||||
}
|
||||
// stem the word
|
||||
var word = stemmer.stemWord(tmp[i]).toLowerCase();
|
||||
// select the correct list
|
||||
if (word[0] == '-') {
|
||||
var toAppend = excluded;
|
||||
word = word.substr(1);
|
||||
}
|
||||
else {
|
||||
var toAppend = searchterms;
|
||||
hlterms.push(tmp[i].toLowerCase());
|
||||
}
|
||||
// only add if not already in the list
|
||||
if (!$.contains(toAppend, word))
|
||||
toAppend.push(word);
|
||||
};
|
||||
var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
|
||||
|
||||
// console.debug('SEARCH: searching for:');
|
||||
// console.info('required: ', searchterms);
|
||||
// console.info('excluded: ', excluded);
|
||||
|
||||
// prepare search
|
||||
var filenames = this._index.filenames;
|
||||
var titles = this._index.titles;
|
||||
var terms = this._index.terms;
|
||||
var objects = this._index.objects;
|
||||
var objtypes = this._index.objtypes;
|
||||
var objnames = this._index.objnames;
|
||||
var fileMap = {};
|
||||
var files = null;
|
||||
// different result priorities
|
||||
var importantResults = [];
|
||||
var objectResults = [];
|
||||
var regularResults = [];
|
||||
var unimportantResults = [];
|
||||
$('#search-progress').empty();
|
||||
|
||||
// lookup as object
|
||||
if (object != null) {
|
||||
for (var prefix in objects) {
|
||||
for (var name in objects[prefix]) {
|
||||
var fullname = (prefix ? prefix + '.' : '') + name;
|
||||
if (fullname.toLowerCase().indexOf(object) > -1) {
|
||||
match = objects[prefix][name];
|
||||
descr = objnames[match[1]] + _(', in ') + titles[match[0]];
|
||||
// XXX the generated anchors are not generally correct
|
||||
// XXX there may be custom prefixes
|
||||
result = [filenames[match[0]], fullname, '#'+fullname, descr];
|
||||
switch (match[2]) {
|
||||
case 1: objectResults.push(result); break;
|
||||
case 0: importantResults.push(result); break;
|
||||
case 2: unimportantResults.push(result); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sort results descending
|
||||
objectResults.sort(function(a, b) {
|
||||
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
|
||||
});
|
||||
|
||||
importantResults.sort(function(a, b) {
|
||||
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
|
||||
});
|
||||
|
||||
unimportantResults.sort(function(a, b) {
|
||||
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
|
||||
});
|
||||
|
||||
|
||||
// perform the search on the required terms
|
||||
for (var i = 0; i < searchterms.length; i++) {
|
||||
var word = searchterms[i];
|
||||
// no match but word was a required one
|
||||
if ((files = terms[word]) == null)
|
||||
break;
|
||||
if (files.length == undefined) {
|
||||
files = [files];
|
||||
}
|
||||
// create the mapping
|
||||
for (var j = 0; j < files.length; j++) {
|
||||
var file = files[j];
|
||||
if (file in fileMap)
|
||||
fileMap[file].push(word);
|
||||
else
|
||||
fileMap[file] = [word];
|
||||
}
|
||||
}
|
||||
|
||||
// now check if the files don't contain excluded terms
|
||||
for (var file in fileMap) {
|
||||
var valid = true;
|
||||
|
||||
// check if all requirements are matched
|
||||
if (fileMap[file].length != searchterms.length)
|
||||
continue;
|
||||
|
||||
// ensure that none of the excluded terms is in the
|
||||
// search result.
|
||||
for (var i = 0; i < excluded.length; i++) {
|
||||
if (terms[excluded[i]] == file ||
|
||||
$.contains(terms[excluded[i]] || [], file)) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have still a valid result we can add it
|
||||
// to the result list
|
||||
if (valid)
|
||||
regularResults.push([filenames[file], titles[file], '', null]);
|
||||
}
|
||||
|
||||
// delete unused variables in order to not waste
|
||||
// memory until list is retrieved completely
|
||||
delete filenames, titles, terms;
|
||||
|
||||
// now sort the regular results descending by title
|
||||
regularResults.sort(function(a, b) {
|
||||
var left = a[1].toLowerCase();
|
||||
var right = b[1].toLowerCase();
|
||||
return (left > right) ? -1 : ((left < right) ? 1 : 0);
|
||||
});
|
||||
|
||||
// combine all results
|
||||
var results = unimportantResults.concat(regularResults)
|
||||
.concat(objectResults).concat(importantResults);
|
||||
|
||||
// print the results
|
||||
var resultCount = results.length;
|
||||
function displayNextItem() {
|
||||
// results left, load the summary and display it
|
||||
if (results.length) {
|
||||
var item = results.pop();
|
||||
var listItem = $('<li style="display:none"></li>');
|
||||
if (DOCUMENTATION_OPTIONS.FILE_SUFFIX == '') {
|
||||
// dirhtml builder
|
||||
var dirname = item[0] + '/';
|
||||
if (dirname.match(/\/index\/$/)) {
|
||||
dirname = dirname.substring(0, dirname.length-6);
|
||||
} else if (dirname == 'index/') {
|
||||
dirname = '';
|
||||
}
|
||||
listItem.append($('<a/>').attr('href',
|
||||
DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
|
||||
highlightstring + item[2]).html(item[1]));
|
||||
} else {
|
||||
// normal html builders
|
||||
listItem.append($('<a/>').attr('href',
|
||||
item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
|
||||
highlightstring + item[2]).html(item[1]));
|
||||
}
|
||||
if (item[3]) {
|
||||
listItem.append($('<span> (' + item[3] + ')</span>'));
|
||||
Search.output.append(listItem);
|
||||
listItem.slideDown(5, function() {
|
||||
displayNextItem();
|
||||
});
|
||||
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
|
||||
$.get(DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' +
|
||||
item[0] + '.txt', function(data) {
|
||||
if (data != '') {
|
||||
listItem.append($.makeSearchSummary(data, searchterms, hlterms));
|
||||
Search.output.append(listItem);
|
||||
}
|
||||
listItem.slideDown(5, function() {
|
||||
displayNextItem();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// no source available, just display title
|
||||
Search.output.append(listItem);
|
||||
listItem.slideDown(5, function() {
|
||||
displayNextItem();
|
||||
});
|
||||
}
|
||||
}
|
||||
// search finished, update title and status message
|
||||
else {
|
||||
Search.stopPulse();
|
||||
Search.title.text(_('Search Results'));
|
||||
if (!resultCount)
|
||||
Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
|
||||
else
|
||||
Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
|
||||
Search.status.fadeIn(500);
|
||||
}
|
||||
}
|
||||
displayNextItem();
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
Search.init();
|
||||
});
|
147
doc/html/_static/sidebar.js
Normal file
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* sidebar.js
|
||||
* ~~~~~~~~~~
|
||||
*
|
||||
* This script makes the Sphinx sidebar collapsible.
|
||||
*
|
||||
* .sphinxsidebar contains .sphinxsidebarwrapper. This script adds
|
||||
* in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton
|
||||
* used to collapse and expand the sidebar.
|
||||
*
|
||||
* When the sidebar is collapsed the .sphinxsidebarwrapper is hidden
|
||||
* and the width of the sidebar and the margin-left of the document
|
||||
* are decreased. When the sidebar is expanded the opposite happens.
|
||||
* This script saves a per-browser/per-session cookie used to
|
||||
* remember the position of the sidebar among the pages.
|
||||
* Once the browser is closed the cookie is deleted and the position
|
||||
* reset to the default (expanded).
|
||||
*
|
||||
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
// global elements used by the functions.
|
||||
// the 'sidebarbutton' element is defined as global after its
|
||||
// creation, in the add_sidebar_button function
|
||||
var bodywrapper = $('.bodywrapper');
|
||||
var sidebar = $('.sphinxsidebar');
|
||||
var sidebarwrapper = $('.sphinxsidebarwrapper');
|
||||
|
||||
// original margin-left of the bodywrapper and width of the sidebar
|
||||
// with the sidebar expanded
|
||||
var bw_margin_expanded = bodywrapper.css('margin-left');
|
||||
var ssb_width_expanded = sidebar.width();
|
||||
|
||||
// margin-left of the bodywrapper and width of the sidebar
|
||||
// with the sidebar collapsed
|
||||
var bw_margin_collapsed = '.8em';
|
||||
var ssb_width_collapsed = '.8em';
|
||||
|
||||
// colors used by the current theme
|
||||
var dark_color = $('.related').css('background-color');
|
||||
var light_color = $('.document').css('background-color');
|
||||
|
||||
function sidebar_is_collapsed() {
|
||||
return sidebarwrapper.is(':not(:visible)');
|
||||
}
|
||||
|
||||
function toggle_sidebar() {
|
||||
if (sidebar_is_collapsed())
|
||||
expand_sidebar();
|
||||
else
|
||||
collapse_sidebar();
|
||||
}
|
||||
|
||||
function collapse_sidebar() {
|
||||
sidebarwrapper.hide();
|
||||
sidebar.css('width', ssb_width_collapsed);
|
||||
bodywrapper.css('margin-left', bw_margin_collapsed);
|
||||
sidebarbutton.css({
|
||||
'margin-left': '0',
|
||||
'height': bodywrapper.height()
|
||||
});
|
||||
sidebarbutton.find('span').text('»');
|
||||
sidebarbutton.attr('title', _('Expand sidebar'));
|
||||
document.cookie = 'sidebar=collapsed';
|
||||
}
|
||||
|
||||
function expand_sidebar() {
|
||||
bodywrapper.css('margin-left', bw_margin_expanded);
|
||||
sidebar.css('width', ssb_width_expanded);
|
||||
sidebarwrapper.show();
|
||||
sidebarbutton.css({
|
||||
'margin-left': ssb_width_expanded-12,
|
||||
'height': bodywrapper.height()
|
||||
});
|
||||
sidebarbutton.find('span').text('«');
|
||||
sidebarbutton.attr('title', _('Collapse sidebar'));
|
||||
document.cookie = 'sidebar=expanded';
|
||||
}
|
||||
|
||||
function add_sidebar_button() {
|
||||
sidebarwrapper.css({
|
||||
'float': 'left',
|
||||
'margin-right': '0',
|
||||
'width': ssb_width_expanded - 28
|
||||
});
|
||||
// create the button
|
||||
sidebar.append(
|
||||
'<div id="sidebarbutton"><span>«</span></div>'
|
||||
);
|
||||
var sidebarbutton = $('#sidebarbutton');
|
||||
// find the height of the viewport to center the '<<' in the page
|
||||
var viewport_height;
|
||||
if (window.innerHeight)
|
||||
viewport_height = window.innerHeight;
|
||||
else
|
||||
viewport_height = $(window).height();
|
||||
sidebarbutton.find('span').css({
|
||||
'display': 'block',
|
||||
'margin-top': (viewport_height - sidebar.position().top - 20) / 2
|
||||
});
|
||||
|
||||
sidebarbutton.click(toggle_sidebar);
|
||||
sidebarbutton.attr('title', _('Collapse sidebar'));
|
||||
sidebarbutton.css({
|
||||
'color': '#FFFFFF',
|
||||
'border-left': '1px solid ' + dark_color,
|
||||
'font-size': '1.2em',
|
||||
'cursor': 'pointer',
|
||||
'height': bodywrapper.height(),
|
||||
'padding-top': '1px',
|
||||
'margin-left': ssb_width_expanded - 12
|
||||
});
|
||||
|
||||
sidebarbutton.hover(
|
||||
function () {
|
||||
$(this).css('background-color', dark_color);
|
||||
},
|
||||
function () {
|
||||
$(this).css('background-color', light_color);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function set_position_from_cookie() {
|
||||
if (!document.cookie)
|
||||
return;
|
||||
var items = document.cookie.split(';');
|
||||
for(var k=0; k<items.length; k++) {
|
||||
var key_val = items[k].split('=');
|
||||
var key = key_val[0];
|
||||
if (key == 'sidebar') {
|
||||
var value = key_val[1];
|
||||
if ((value == 'collapsed') && (!sidebar_is_collapsed()))
|
||||
collapse_sidebar();
|
||||
else if ((value == 'expanded') && (sidebar_is_collapsed()))
|
||||
expand_sidebar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_sidebar_button();
|
||||
var sidebarbutton = $('#sidebarbutton');
|
||||
set_position_from_cookie();
|
||||
});
|
16
doc/html/_static/underscore.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
(function(){var j=this,n=j._,i=function(a){this._wrapped=a},m=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=j._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;var k=Array.prototype.slice,o=Array.prototype.unshift,p=Object.prototype.toString,q=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;b.VERSION="0.5.5";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(b.isArray(a)||b.isArguments(a))for(var e=0,f=a.length;e<f;e++)c.call(d,
|
||||
a[e],e,a);else{var g=b.keys(a);f=g.length;for(e=0;e<f;e++)c.call(d,a[g[e]],g[e],a)}}catch(h){if(h!=m)throw h;}return a};b.map=function(a,c,d){if(a&&b.isFunction(a.map))return a.map(c,d);var e=[];b.each(a,function(f,g,h){e.push(c.call(d,f,g,h))});return e};b.reduce=function(a,c,d,e){if(a&&b.isFunction(a.reduce))return a.reduce(b.bind(d,e),c);b.each(a,function(f,g,h){c=d.call(e,c,f,g,h)});return c};b.reduceRight=function(a,c,d,e){if(a&&b.isFunction(a.reduceRight))return a.reduceRight(b.bind(d,e),c);
|
||||
var f=b.clone(b.toArray(a)).reverse();b.each(f,function(g,h){c=d.call(e,c,g,h,a)});return c};b.detect=function(a,c,d){var e;b.each(a,function(f,g,h){if(c.call(d,f,g,h)){e=f;b.breakLoop()}});return e};b.select=function(a,c,d){if(a&&b.isFunction(a.filter))return a.filter(c,d);var e=[];b.each(a,function(f,g,h){c.call(d,f,g,h)&&e.push(f)});return e};b.reject=function(a,c,d){var e=[];b.each(a,function(f,g,h){!c.call(d,f,g,h)&&e.push(f)});return e};b.all=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.every))return a.every(c,
|
||||
d);var e=true;b.each(a,function(f,g,h){(e=e&&c.call(d,f,g,h))||b.breakLoop()});return e};b.any=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.some))return a.some(c,d);var e=false;b.each(a,function(f,g,h){if(e=c.call(d,f,g,h))b.breakLoop()});return e};b.include=function(a,c){if(b.isArray(a))return b.indexOf(a,c)!=-1;var d=false;b.each(a,function(e){if(d=e===c)b.breakLoop()});return d};b.invoke=function(a,c){var d=b.rest(arguments,2);return b.map(a,function(e){return(c?e[c]:e).apply(e,d)})};b.pluck=
|
||||
function(a,c){return b.map(a,function(d){return d[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);var e={computed:-Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g>=e.computed&&(e={value:f,computed:g})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g<e.computed&&(e={value:f,computed:g})});return e.value};b.sortBy=function(a,c,d){return b.pluck(b.map(a,
|
||||
function(e,f,g){return{value:e,criteria:c.call(d,e,f,g)}}).sort(function(e,f){e=e.criteria;f=f.criteria;return e<f?-1:e>f?1:0}),"value")};b.sortedIndex=function(a,c,d){d=d||b.identity;for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?(e=g+1):(f=g)}return e};b.toArray=function(a){if(!a)return[];if(a.toArray)return a.toArray();if(b.isArray(a))return a;if(b.isArguments(a))return k.call(a);return b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=function(a,c,d){return c&&!d?k.call(a,
|
||||
0,c):a[0]};b.rest=function(a,c,d){return k.call(a,b.isUndefined(c)||d?1:c)};b.last=function(a){return a[a.length-1]};b.compact=function(a){return b.select(a,function(c){return!!c})};b.flatten=function(a){return b.reduce(a,[],function(c,d){if(b.isArray(d))return c.concat(b.flatten(d));c.push(d);return c})};b.without=function(a){var c=b.rest(arguments);return b.select(a,function(d){return!b.include(c,d)})};b.uniq=function(a,c){return b.reduce(a,[],function(d,e,f){if(0==f||(c===true?b.last(d)!=e:!b.include(d,
|
||||
e)))d.push(e);return d})};b.intersect=function(a){var c=b.rest(arguments);return b.select(b.uniq(a),function(d){return b.all(c,function(e){return b.indexOf(e,d)>=0})})};b.zip=function(){for(var a=b.toArray(arguments),c=b.max(b.pluck(a,"length")),d=new Array(c),e=0;e<c;e++)d[e]=b.pluck(a,String(e));return d};b.indexOf=function(a,c){if(a.indexOf)return a.indexOf(c);for(var d=0,e=a.length;d<e;d++)if(a[d]===c)return d;return-1};b.lastIndexOf=function(a,c){if(a.lastIndexOf)return a.lastIndexOf(c);for(var d=
|
||||
a.length;d--;)if(a[d]===c)return d;return-1};b.range=function(a,c,d){var e=b.toArray(arguments),f=e.length<=1;a=f?0:e[0];c=f?e[0]:e[1];d=e[2]||1;e=Math.ceil((c-a)/d);if(e<=0)return[];e=new Array(e);f=a;for(var g=0;1;f+=d){if((d>0?f-c:c-f)>=0)return e;e[g++]=f}};b.bind=function(a,c){var d=b.rest(arguments,2);return function(){return a.apply(c||j,d.concat(b.toArray(arguments)))}};b.bindAll=function(a){var c=b.rest(arguments);if(c.length==0)c=b.functions(a);b.each(c,function(d){a[d]=b.bind(a[d],a)});
|
||||
return a};b.delay=function(a,c){var d=b.rest(arguments,2);return setTimeout(function(){return a.apply(a,d)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(b.rest(arguments)))};b.wrap=function(a,c){return function(){var d=[a].concat(b.toArray(arguments));return c.apply(c,d)}};b.compose=function(){var a=b.toArray(arguments);return function(){for(var c=b.toArray(arguments),d=a.length-1;d>=0;d--)c=[a[d].apply(this,c)];return c[0]}};b.keys=function(a){if(b.isArray(a))return b.range(0,a.length);
|
||||
var c=[];for(var d in a)q.call(a,d)&&c.push(d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=function(a){return b.select(b.keys(a),function(c){return b.isFunction(a[c])}).sort()};b.extend=function(a,c){for(var d in c)a[d]=c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);return b.extend({},a)};b.tap=function(a,c){c(a);return a};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a;if(d!=typeof c)return false;if(a==c)return true;if(!a&&c||a&&!c)return false;
|
||||
if(a.isEqual)return a.isEqual(c);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return true;if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return false;if(a.length&&a.length!==c.length)return false;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty=function(a){return b.keys(a).length==
|
||||
0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=function(a){return!!(a&&a.concat&&a.unshift)};b.isArguments=function(a){return a&&b.isNumber(a.length)&&!b.isArray(a)&&!r.call(a,"length")};b.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return p.call(a)==="[object Number]"};b.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};b.isRegExp=function(a){return!!(a&&
|
||||
a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};b.isNaN=function(a){return b.isNumber(a)&&isNaN(a)};b.isNull=function(a){return a===null};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){j._=n;return this};b.identity=function(a){return a};b.breakLoop=function(){throw m;};var s=0;b.uniqueId=function(a){var c=s++;return a?a+c:c};b.template=function(a,c){a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g,
|
||||
" ").replace(/'(?=[^%]*%>)/g,"\t").split("'").join("\\'").split("\t").join("'").replace(/<%=(.+?)%>/g,"',$1,'").split("<%").join("');").split("%>").join("p.push('")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.head=b.first;b.tail=b.rest;b.methods=b.functions;var l=function(a,c){return c?b(a).chain():a};b.each(b.functions(b),function(a){var c=b[a];i.prototype[a]=function(){var d=b.toArray(arguments);
|
||||
o.call(d,this._wrapped);return l(c.apply(b,d),this._chain)}});b.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){c.apply(this._wrapped,arguments);return l(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){return l(c.apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})();
|
220
doc/html/api/css/style.css
Normal file
|
@ -0,0 +1,220 @@
|
|||
body
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
color: black;
|
||||
background-color: #1f252b;
|
||||
font-size: 100%;
|
||||
font-family: Verdana, "Deja Vu", "Bitstream Vera Sans", sans-serif;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6
|
||||
{
|
||||
font-family: Georgia, "Times New Roman", Times, serif;
|
||||
font-weight: normal;
|
||||
color: #633;
|
||||
line-height: normal;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h1
|
||||
{
|
||||
margin-top: 0;
|
||||
font-size: 2.5em;
|
||||
}
|
||||
|
||||
h2{font-size: 1.7em;}
|
||||
|
||||
h3{font-size: 1.35em;}
|
||||
|
||||
h4
|
||||
{
|
||||
font-size: 1.15em;
|
||||
font-style: italic;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
pre
|
||||
{
|
||||
background: #eef;
|
||||
padding: 1ex;
|
||||
margin: 1em 0 1em 3em;
|
||||
font-family: monospace;
|
||||
font-size: 1.2em;
|
||||
line-height: normal;
|
||||
border: 1px solid #ccc;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
dd
|
||||
{
|
||||
padding: 1ex;
|
||||
margin-left: 3em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
td{text-align: justify;}
|
||||
|
||||
hr{margin: 2em 0;}
|
||||
|
||||
a{color: #006;}
|
||||
|
||||
a:visited{color: #606;}
|
||||
|
||||
/* These are different kinds of <pre> sections */
|
||||
.console /* command line console */
|
||||
{
|
||||
background-color: #f7f7f7;
|
||||
color: #181818;
|
||||
}
|
||||
|
||||
.moddeffile /* module definition file */
|
||||
{
|
||||
background-color: #efeffe;
|
||||
color: #010199;
|
||||
}
|
||||
|
||||
.d_code /* D code */
|
||||
{
|
||||
background-color: #fcfcfc;
|
||||
color: #000066;
|
||||
}
|
||||
|
||||
.d_code2 /* D code */
|
||||
{
|
||||
background-color: #fcfcfc;
|
||||
color: #000066;
|
||||
}
|
||||
|
||||
td .d_code2
|
||||
{
|
||||
min-width: 20em;
|
||||
margin: 1em 0em;
|
||||
}
|
||||
|
||||
.d_inlinecode
|
||||
{
|
||||
font-family: monospace;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Elements of D source code text */
|
||||
.d_comment{color: green;}
|
||||
.d_string {color: red;}
|
||||
.d_keyword{color: blue;}
|
||||
.d_psymbol{text-decoration: underline;}
|
||||
.d_param {font-style: italic;}
|
||||
|
||||
/* Focal symbol that is being documented */
|
||||
.ddoc_psymbol{color: #336600;}
|
||||
|
||||
div#top{max-width: 85em;}
|
||||
|
||||
div#header{padding: 0.2em 1em 0.2em 1em;}
|
||||
div.pbr
|
||||
{
|
||||
margin: 4px 0px 8px 10px}
|
||||
|
||||
img#logo{vertical-align: bottom;}
|
||||
|
||||
#main-heading
|
||||
{
|
||||
margin-left: 1em;
|
||||
color: white;
|
||||
font-size: 1.4em;
|
||||
font-family: Arial, Verdana, sans-serif;
|
||||
font-variant: small-caps;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div#navigation
|
||||
{
|
||||
font-size: 0.875em;
|
||||
float: left;
|
||||
width: 12.0em;
|
||||
padding: 0 1.5em;
|
||||
}
|
||||
|
||||
div.navblock
|
||||
{
|
||||
margin-top: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
div#navigation .navblock h2
|
||||
{
|
||||
font-family: Verdana, "Deja Vu", "Bitstream Vera Sans", sans-serif;
|
||||
font-size: 1.35em;
|
||||
color: #ccc;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div#navigation .navblock ul
|
||||
{
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div#navigation .navblock li
|
||||
{
|
||||
margin: 0 0 0 0.8em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#navigation .navblock a
|
||||
{
|
||||
display: block;
|
||||
color: #ddd;
|
||||
text-decoration: none;
|
||||
padding: 0.1em 0;
|
||||
border-bottom: 1px dashed #444;
|
||||
}
|
||||
|
||||
#navigation .navblock a:hover{color: white;}
|
||||
|
||||
#navigation .navblock a.active
|
||||
{
|
||||
color: white;
|
||||
border-color: white;
|
||||
}
|
||||
|
||||
div#content
|
||||
{
|
||||
min-height: 440px;
|
||||
margin-left: 15em;
|
||||
margin-right: 1.6em;
|
||||
padding: 1.6em;
|
||||
padding-top: 1.3em;
|
||||
border: 0.6em solid #cccccc;
|
||||
background-color: #f6f6f6;
|
||||
font-size: 0.875em;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
div#content li{padding-bottom: .7ex;}
|
||||
|
||||
div#copyright
|
||||
{
|
||||
padding: 1em 2em;
|
||||
background-color: #303333;
|
||||
color: #ccc;
|
||||
font-size: 0.75em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div#copyright a{color: #ccc;}
|
||||
|
||||
.d_inlinecode
|
||||
{
|
||||
font-family: Consolas, "Bitstream Vera Sans Mono", "Andale Mono", "DejaVu Sans Mono", "Lucida Console", monospace;
|
||||
}
|
||||
|
||||
.d_decl
|
||||
{
|
||||
font-weight: bold;
|
||||
background-color: #E4E9EF;
|
||||
border-bottom: solid 2px #336600;
|
||||
padding: 2px 0px 2px 2px;
|
||||
}
|
192
doc/html/api/dyaml.constructor.html
Normal file
|
@ -0,0 +1,192 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" >
|
||||
<title>dyaml.constructor - D:YAML 0.1 API documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css">
|
||||
</head>
|
||||
|
||||
<body><div id="top">
|
||||
<div id="header">
|
||||
<img id="logo" alt="D:YAML logo" src="images/logo.png"><a id="main-heading" href="index.html">D:YAML 0.1 API documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="navigation">
|
||||
<div class="navblock">
|
||||
<div id="toctop">
|
||||
<ul><li><a href="../index.html">Documentation home</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navblock">
|
||||
<ul><li><a href="index.html">Main page</a></li>
|
||||
<li><a href="dyaml.constructor.html">dyaml.constructor</a></li>
|
||||
<li><a href="dyaml.exception.html">dyaml.exception</a></li>
|
||||
<li><a href="dyaml.loader.html">dyaml.loader</a></li>
|
||||
<li><a href="dyaml.node.html">dyaml.node</a></li>
|
||||
<li><a href="dyaml.resolver.html">dyaml.resolver</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<h1>dyaml.constructor</h1>
|
||||
<!-- Generated by Ddoc from dyaml/constructor.d -->
|
||||
<p>Implements a class that processes YAML mappings, sequences and scalars into
|
||||
nodes. This can be used to implement custom data types. A tutorial can be
|
||||
found <a href="../tutorials/custom_types.html">here</a>.</p>
|
||||
|
||||
<dl><dt class="d_decl">class <a name="ConstructorException"></a><span class="ddoc_psymbol">ConstructorException</span>: dyaml.exception.YAMLException;
|
||||
</dt>
|
||||
<dd><p>Exception thrown at constructor errors.
|
||||
</p>
|
||||
<p>Can be thrown by custom constructor functions.</p>
|
||||
|
||||
<dl><dt class="d_decl">this(string <b>msg</b>, Mark <b>start</b>, Mark <b>end</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a ConstructorException.
|
||||
</p>
|
||||
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>string <b>msg</b></td>
|
||||
<td valign=top>Error message.</td></tr>
|
||||
<tr><td valign=top>Mark <b>start</b></td>
|
||||
<td valign=top>Start position of the error context.</td></tr>
|
||||
<tr><td valign=top>Mark <b>end</b></td>
|
||||
<td valign=top>End position of the error context.</td></tr>
|
||||
</table></div>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt class="d_decl">class <a name="Constructor"></a><span class="ddoc_psymbol">Constructor</span>;
|
||||
</dt>
|
||||
<dd><p>Constructs YAML values.
|
||||
</p>
|
||||
<p>Each YAML scalar, sequence or mapping has a tag specifying its data type.
|
||||
<a name="Constructor"></a><span class="ddoc_psymbol">Constructor</span> uses user-specifyable functions to create a node of desired
|
||||
data type from a scalar, sequence or mapping.
|
||||
<br>
|
||||
|
||||
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.
|
||||
<br>
|
||||
|
||||
If a tag is detected with no known constructor function, it is considered an error.</p>
|
||||
|
||||
<dl><dt class="d_decl">this(in bool <b>defaultConstructors</b> = true);
|
||||
</dt>
|
||||
<dd><p>Construct a Constructor.
|
||||
</p>
|
||||
<p>If you don't want to support default YAML tags/data types, you can use
|
||||
<b>defaultConstructors</b> to disable constructor functions for these.
|
||||
|
||||
</p>
|
||||
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>bool <b>defaultConstructors</b></td>
|
||||
<td valign=top>Use constructors for default YAML tags?</td></tr>
|
||||
</table></div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">void <a name="addConstructor"></a><span class="ddoc_psymbol">addConstructor</span>(T, U)(in string <b>tag</b>, T function(Mark, Mark, U) <b>ctor</b>);
|
||||
</dt>
|
||||
<dd><p>Add a constructor function.
|
||||
</p>
|
||||
<p>The function passed must two Marks (determining start and end positions of
|
||||
the node in file) and either a string (if constructing from scalar),
|
||||
an array of Nodes (from sequence) or an array of Node.Pair (from mapping).
|
||||
The value returned by this function will be stored in the resulring node.
|
||||
|
||||
</p>
|
||||
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>tag</td>
|
||||
<td valign=top>Tag for the function to handle.</td></tr>
|
||||
<tr><td valign=top>ctor</td>
|
||||
<td valign=top>Constructor function.</td></tr>
|
||||
</table></div>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt class="d_decl">YAMLNull <a name="constructNull"></a><span class="ddoc_psymbol">constructNull</span>(Mark <b>start</b>, Mark <b>end</b>, string <b>value</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a <b>null</b> node.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">YAMLMerge <a name="constructMerge"></a><span class="ddoc_psymbol">constructMerge</span>(Mark <b>start</b>, Mark <b>end</b>, string <b>value</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a merge node - a node that merges another node into a mapping.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">bool <a name="constructBool"></a><span class="ddoc_psymbol">constructBool</span>(Mark <b>start</b>, Mark <b>end</b>, string <b>value</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a boolean node.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">long <a name="constructLong"></a><span class="ddoc_psymbol">constructLong</span>(Mark <b>start</b>, Mark <b>end</b>, string <b>value</b>);
|
||||
</dt>
|
||||
<dd><p>Construct an integer (long) node.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">real <a name="constructReal"></a><span class="ddoc_psymbol">constructReal</span>(Mark <b>start</b>, Mark <b>end</b>, string <b>value</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a floating point (real) node.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">ubyte[] <a name="constructBinary"></a><span class="ddoc_psymbol">constructBinary</span>(Mark <b>start</b>, Mark <b>end</b>, string <b>value</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a binary (base64) node.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">SysTime <a name="constructTimestamp"></a><span class="ddoc_psymbol">constructTimestamp</span>(Mark <b>start</b>, Mark <b>end</b>, string <b>value</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a timestamp (SysTime) node.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">string <a name="constructString"></a><span class="ddoc_psymbol">constructString</span>(Mark <b>start</b>, Mark <b>end</b>, string <b>value</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a string node.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">Pair[] <a name="getPairs"></a><span class="ddoc_psymbol">getPairs</span>(string <b>type</b>, Mark <b>start</b>, Mark <b>end</b>, Node[] <b>nodes</b>);
|
||||
</dt>
|
||||
<dd><p>Convert a sequence of single-element mappings into a sequence of pairs.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">Pair[] <a name="constructOrderedMap"></a><span class="ddoc_psymbol">constructOrderedMap</span>(Mark <b>start</b>, Mark <b>end</b>, Node[] <b>nodes</b>);
|
||||
</dt>
|
||||
<dd><p>Construct an ordered map (ordered sequence of key:value pairs without duplicates) node.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">Pair[] <a name="constructPairs"></a><span class="ddoc_psymbol">constructPairs</span>(Mark <b>start</b>, Mark <b>end</b>, Node[] <b>nodes</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a pairs (ordered sequence of key: value pairs allowing duplicates) node.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">Node[] <a name="constructSet"></a><span class="ddoc_psymbol">constructSet</span>(Mark <b>start</b>, Mark <b>end</b>, Pair[] <b>pairs</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a set node.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">Node[] <a name="constructSequence"></a><span class="ddoc_psymbol">constructSequence</span>(Mark <b>start</b>, Mark <b>end</b>, Node[] <b>nodes</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a sequence (array) node.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">Pair[] <a name="constructMap"></a><span class="ddoc_psymbol">constructMap</span>(Mark <b>start</b>, Mark <b>end</b>, Pair[] <b>pairs</b>);
|
||||
</dt>
|
||||
<dd><p>Construct an unordered map (unordered set of key: value pairs without duplicates) node.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="copyright">
|
||||
Copyright © Ferdinand Majerech 2011. Based on <a href="http://www.pyyaml.org">PyYAML</a> by Kirill Simonov. |
|
||||
Page generated by Autodoc and <a href="http://www.digitalmars.com/d/2.0/ddoc.html">Ddoc</a>.
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
78
doc/html/api/dyaml.exception.html
Normal file
|
@ -0,0 +1,78 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" >
|
||||
<title>dyaml.exception - D:YAML 0.1 API documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css">
|
||||
</head>
|
||||
|
||||
<body><div id="top">
|
||||
<div id="header">
|
||||
<img id="logo" alt="D:YAML logo" src="images/logo.png"><a id="main-heading" href="index.html">D:YAML 0.1 API documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="navigation">
|
||||
<div class="navblock">
|
||||
<div id="toctop">
|
||||
<ul><li><a href="../index.html">Documentation home</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navblock">
|
||||
<ul><li><a href="index.html">Main page</a></li>
|
||||
<li><a href="dyaml.constructor.html">dyaml.constructor</a></li>
|
||||
<li><a href="dyaml.exception.html">dyaml.exception</a></li>
|
||||
<li><a href="dyaml.loader.html">dyaml.loader</a></li>
|
||||
<li><a href="dyaml.node.html">dyaml.node</a></li>
|
||||
<li><a href="dyaml.resolver.html">dyaml.resolver</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<h1>dyaml.exception</h1>
|
||||
<!-- Generated by Ddoc from dyaml/exception.d -->
|
||||
<p><b>D:</b><br>
|
||||
YAML exceptions and <a name="exception"></a><span class="ddoc_psymbol">exception</span> related code.</p>
|
||||
|
||||
<dl><dt class="d_decl">class <a name="YAMLException"></a><span class="ddoc_psymbol">YAMLException</span>: object.Exception;
|
||||
</dt>
|
||||
<dd><p>Base class for all exceptions thrown by D:YAML.</p>
|
||||
|
||||
<dl><dt class="d_decl">this(string <b>msg</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a YAMLException with specified message.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt class="d_decl">struct <a name="Mark"></a><span class="ddoc_psymbol">Mark</span>;
|
||||
</dt>
|
||||
<dd><p>Position in a YAML stream, used for error messages.</p>
|
||||
|
||||
<dl><dt class="d_decl">this(in uint <b>line</b>, in uint <b>column</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a Mark with specified <b>line</b> and <b>column</b> in the file.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">const string <a name="toString"></a><span class="ddoc_psymbol">toString</span>();
|
||||
</dt>
|
||||
<dd><p>Get a string representation of the mark.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="copyright">
|
||||
Copyright © Ferdinand Majerech 2011. Based on <a href="http://www.pyyaml.org">PyYAML</a> by Kirill Simonov. |
|
||||
Page generated by Autodoc and <a href="http://www.digitalmars.com/d/2.0/ddoc.html">Ddoc</a>.
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
216
doc/html/api/dyaml.loader.html
Normal file
|
@ -0,0 +1,216 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" >
|
||||
<title>dyaml.loader - D:YAML 0.1 API documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css">
|
||||
</head>
|
||||
|
||||
<body><div id="top">
|
||||
<div id="header">
|
||||
<img id="logo" alt="D:YAML logo" src="images/logo.png"><a id="main-heading" href="index.html">D:YAML 0.1 API documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="navigation">
|
||||
<div class="navblock">
|
||||
<div id="toctop">
|
||||
<ul><li><a href="../index.html">Documentation home</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navblock">
|
||||
<ul><li><a href="index.html">Main page</a></li>
|
||||
<li><a href="dyaml.constructor.html">dyaml.constructor</a></li>
|
||||
<li><a href="dyaml.exception.html">dyaml.exception</a></li>
|
||||
<li><a href="dyaml.loader.html">dyaml.loader</a></li>
|
||||
<li><a href="dyaml.node.html">dyaml.node</a></li>
|
||||
<li><a href="dyaml.resolver.html">dyaml.resolver</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<h1>dyaml.loader</h1>
|
||||
<!-- Generated by Ddoc from dyaml/loader.d -->
|
||||
<p>Class and convenience functions used to load YAML documents.</p>
|
||||
|
||||
<dl><dt class="d_decl">Node <a name="load"></a><span class="ddoc_psymbol">load</span>(in string <b>filename</b>);
|
||||
</dt>
|
||||
<dd><p>Load single YAML document from a file.
|
||||
</p>
|
||||
<p>If there is no or more than one YAML document in the file, this will throw.
|
||||
Use <a href="#loadAll"><span class="d_inlinecode">loadAll</span></a> for such files.
|
||||
|
||||
</p>
|
||||
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>string <b>filename</b></td>
|
||||
<td valign=top>Name of the file to load from.</td></tr>
|
||||
</table></div>
|
||||
<b>Returns:</b><div class="pbr">Root node of the document.
|
||||
|
||||
</div>
|
||||
<b>Throws:</b><div class="pbr">YAMLException if there wasn't exactly one document in the file,
|
||||
the file could not be opened or on a YAML parsing error.</div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">Node <a name="load"></a><span class="ddoc_psymbol">load</span>(Stream <b>input</b>, in string <b>name</b> = "<unknown>");
|
||||
</dt>
|
||||
<dd><p>Load single YAML document from a stream.
|
||||
</p>
|
||||
<p>You can use this to e.g load YAML from memory.
|
||||
<br>
|
||||
|
||||
If there is no or more than one YAML document in the stream, this will throw.
|
||||
Use <a href="#loadAll"><span class="d_inlinecode">loadAll</span></a> for such files.
|
||||
|
||||
</p>
|
||||
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>Stream <b>input</b></td>
|
||||
<td valign=top>Stream to read from. Must be readable.</td></tr>
|
||||
<tr><td valign=top>string <b>name</b></td>
|
||||
<td valign=top>Name of the stream, used in error messages.</td></tr>
|
||||
</table></div>
|
||||
<b>Returns:</b><div class="pbr">Root node of the document.
|
||||
|
||||
</div>
|
||||
<b>Throws:</b><div class="pbr">YAMLException if there wasn't exactly one document in the stream,
|
||||
the stream could not be read from or on a YAML parsing error.
|
||||
|
||||
</div>
|
||||
<b>Examples:</b><div class="pbr">Loading YAML from memory:
|
||||
<pre class="d_code"> <span class="d_keyword">import</span> std.stream;
|
||||
<span class="d_keyword">import</span> std.stdio;
|
||||
|
||||
string yaml_input = <span class="d_string">"red: '#ff0000'\n"</span>
|
||||
<span class="d_string">"green: '#00ff00'\n"</span>
|
||||
<span class="d_string">"blue: '#0000ff'"</span>;
|
||||
|
||||
<span class="d_keyword">auto</span> colors = yaml.<span class="d_psymbol">load</span>(<span class="d_keyword">new</span> MemoryStream(<span class="d_keyword">cast</span>(<span class="d_keyword">char</span>[])yaml_input));
|
||||
|
||||
<span class="d_keyword">foreach</span>(string color, string value; colors)
|
||||
{
|
||||
writeln(color, <span class="d_string">" is "</span>, value, <span class="d_string">" in HTML/CSS"</span>);
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">Node[] <a name="loadAll"></a><span class="ddoc_psymbol">loadAll</span>(in string <b>filename</b>);
|
||||
</dt>
|
||||
<dd><p>Load all YAML documents from a file.
|
||||
</p>
|
||||
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>string <b>filename</b></td>
|
||||
<td valign=top>Name of the file to load from.</td></tr>
|
||||
</table></div>
|
||||
<b>Returns:</b><div class="pbr">Array of root nodes of documents in the stream.
|
||||
If the stream is empty, empty array will be returned.
|
||||
|
||||
</div>
|
||||
<b>Throws:</b><div class="pbr">YAMLException if the file could not be opened or on a YAML parsing error.</div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">Node[] <a name="loadAll"></a><span class="ddoc_psymbol">loadAll</span>(Stream <b>input</b>, in string <b>name</b> = "<unknown>");
|
||||
</dt>
|
||||
<dd><p>Load all YAML documents from a stream.
|
||||
</p>
|
||||
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>Stream <b>input</b></td>
|
||||
<td valign=top>Stream to read from. Must be readable.</td></tr>
|
||||
<tr><td valign=top>string <b>name</b></td>
|
||||
<td valign=top>Name of the stream, used in error messages.</td></tr>
|
||||
</table></div>
|
||||
<b>Returns:</b><div class="pbr">Array of root nodes of documents in the file.
|
||||
If the file is empty, empty array will be returned.
|
||||
|
||||
</div>
|
||||
<b>Throws:</b><div class="pbr">YAMLException if the stream could not be read from or on a YAML parsing error.</div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">struct <a name="Loader"></a><span class="ddoc_psymbol">Loader</span>;
|
||||
</dt>
|
||||
<dd><p>Loads YAML documents from files or streams.</p>
|
||||
|
||||
<dl><dt class="d_decl">this(in string <b>filename</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a Loader to load YAML from a file.
|
||||
</p>
|
||||
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>string <b>filename</b></td>
|
||||
<td valign=top>Name of the file to load from.</td></tr>
|
||||
</table></div>
|
||||
<b>Throws:</b><div class="pbr">YAMLException if the file could not be opened or read from.</div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">this(in string <b>filename</b>, Constructor <b>constructor</b>, Resolver <b>resolver</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a Loader to load YAML from a file, with provided constructor and resolver.
|
||||
</p>
|
||||
<p>Constructor and resolver can be used to implement custom data types in YAML.
|
||||
|
||||
</p>
|
||||
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>string <b>filename</b></td>
|
||||
<td valign=top>Name of the file to load from.</td></tr>
|
||||
<tr><td valign=top>Constructor <b>constructor</b></td>
|
||||
<td valign=top>Constructor to use.</td></tr>
|
||||
<tr><td valign=top>Resolver <b>resolver</b></td>
|
||||
<td valign=top>Resolver to use.</td></tr>
|
||||
</table></div>
|
||||
<b>Throws:</b><div class="pbr">YAMLException if the file could not be opened or read from.</div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">this(Stream <b>input</b>, in string <b>name</b>, Constructor <b>constructor</b>, Resolver <b>resolver</b>);
|
||||
</dt>
|
||||
<dd><p>Construct a Loader to load YAML from a stream with provided constructor and resolver.
|
||||
</p>
|
||||
<p>Stream can be used to load YAML from memory and other sources.
|
||||
Constructor and resolver can be used to implement custom data types in YAML.
|
||||
|
||||
</p>
|
||||
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>Stream <b>input</b></td>
|
||||
<td valign=top>Stream to read from. Must be readable.</td></tr>
|
||||
<tr><td valign=top>string <b>name</b></td>
|
||||
<td valign=top>Name of the stream. Used in error messages.</td></tr>
|
||||
<tr><td valign=top>Constructor <b>constructor</b></td>
|
||||
<td valign=top>Constructor to use.</td></tr>
|
||||
<tr><td valign=top>Resolver <b>resolver</b></td>
|
||||
<td valign=top>Resolver to use.</td></tr>
|
||||
</table></div>
|
||||
<b>Throws:</b><div class="pbr">YAMLException if the stream could not be read from.</div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">Node <a name="loadSingleDocument"></a><span class="ddoc_psymbol">loadSingleDocument</span>();
|
||||
</dt>
|
||||
<dd><p>Load single YAML document.
|
||||
</p>
|
||||
<p>If no or more than one YAML document is found, this will throw a YAMLException.
|
||||
|
||||
</p>
|
||||
<b>Returns:</b><div class="pbr">Root node of the document.
|
||||
|
||||
</div>
|
||||
<b>Throws:</b><div class="pbr">YAMLException if there wasn't exactly one document
|
||||
or on a YAML parsing error.</div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">int <a name="opApply"></a><span class="ddoc_psymbol">opApply</span>(int delegate(ref Node) <b>dg</b>);
|
||||
</dt>
|
||||
<dd><p>Foreach over YAML documents.
|
||||
</p>
|
||||
<p>Parses documents lazily, as they are needed.
|
||||
|
||||
</p>
|
||||
<b>Throws:</b><div class="pbr">YAMLException on a parsing error.</div>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="copyright">
|
||||
Copyright © Ferdinand Majerech 2011. Based on <a href="http://www.pyyaml.org">PyYAML</a> by Kirill Simonov. |
|
||||
Page generated by Autodoc and <a href="http://www.digitalmars.com/d/2.0/ddoc.html">Ddoc</a>.
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
260
doc/html/api/dyaml.node.html
Normal file
|
@ -0,0 +1,260 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" >
|
||||
<title>dyaml.node - D:YAML 0.1 API documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css">
|
||||
</head>
|
||||
|
||||
<body><div id="top">
|
||||
<div id="header">
|
||||
<img id="logo" alt="D:YAML logo" src="images/logo.png"><a id="main-heading" href="index.html">D:YAML 0.1 API documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="navigation">
|
||||
<div class="navblock">
|
||||
<div id="toctop">
|
||||
<ul><li><a href="../index.html">Documentation home</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navblock">
|
||||
<ul><li><a href="index.html">Main page</a></li>
|
||||
<li><a href="dyaml.constructor.html">dyaml.constructor</a></li>
|
||||
<li><a href="dyaml.exception.html">dyaml.exception</a></li>
|
||||
<li><a href="dyaml.loader.html">dyaml.loader</a></li>
|
||||
<li><a href="dyaml.node.html">dyaml.node</a></li>
|
||||
<li><a href="dyaml.resolver.html">dyaml.resolver</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<h1>dyaml.node</h1>
|
||||
<!-- Generated by Ddoc from dyaml/node.d -->
|
||||
<p>Node of a YAML document. Used to read YAML data once it's loaded.</p>
|
||||
|
||||
<dl><dt class="d_decl">class <a name="NodeException"></a><span class="ddoc_psymbol">NodeException</span>: dyaml.exception.YAMLException;
|
||||
</dt>
|
||||
<dd><p>Exception thrown at node related errors.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">struct <a name="YAMLNull"></a><span class="ddoc_psymbol">YAMLNull</span>;
|
||||
</dt>
|
||||
<dd><p>Null YAML type. Used in nodes with null values.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">struct <a name="Node"></a><span class="ddoc_psymbol">Node</span>;
|
||||
</dt>
|
||||
<dd><p>YAML node.
|
||||
</p>
|
||||
<p>This is a pseudo-dynamic type that can store any YAML value, including sequence
|
||||
or a mapping of nodes. You can get data from a <a name="Node"></a><span class="ddoc_psymbol">Node</span> directly or iterate over it
|
||||
if it's a sequence or a mapping.</p>
|
||||
|
||||
<dl><dt class="d_decl">struct <a name="Pair"></a><span class="ddoc_psymbol">Pair</span>;
|
||||
</dt>
|
||||
<dd><p><a name="Pair"></a><span class="ddoc_psymbol">Pair</span> of YAML nodes, used in mappings.</p>
|
||||
|
||||
<dl><dt class="d_decl">Node <a name="key"></a><span class="ddoc_psymbol">key</span>;
|
||||
</dt>
|
||||
<dd><p>Key node.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">Node <a name="value"></a><span class="ddoc_psymbol">value</span>;
|
||||
</dt>
|
||||
<dd><p>Value node.</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">bool <a name="equals"></a><span class="ddoc_psymbol">equals</span>(ref Pair <b>rhs</b>);
|
||||
</dt>
|
||||
<dd><p>Test for equality with another Pair.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt class="d_decl">const @property bool <a name="isValid"></a><span class="ddoc_psymbol">isValid</span>();
|
||||
</dt>
|
||||
<dd><p>Is this node valid (initialized)? </p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">const @property bool <a name="isScalar"></a><span class="ddoc_psymbol">isScalar</span>();
|
||||
</dt>
|
||||
<dd><p>Is this node a scalar value?</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">const @property bool <a name="isSequence"></a><span class="ddoc_psymbol">isSequence</span>();
|
||||
</dt>
|
||||
<dd><p>Is this node a sequence of nodes?</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">const @property bool <a name="isMapping"></a><span class="ddoc_psymbol">isMapping</span>();
|
||||
</dt>
|
||||
<dd><p>Is this node a mapping of nodes?</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">const @property bool <a name="isUserType"></a><span class="ddoc_psymbol">isUserType</span>();
|
||||
</dt>
|
||||
<dd><p>Is this node a user defined type?</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">bool <a name="opEquals"></a><span class="ddoc_psymbol">opEquals</span>(T)(ref T <b>rhs</b>);
|
||||
</dt>
|
||||
<dd><p>Equality test.
|
||||
</p>
|
||||
<p>If T is Node, recursively compare all
|
||||
subnodes and might be quite expensive if testing entire documents.
|
||||
<br>
|
||||
|
||||
If T is not Node, convert the node to T and test equality with that.
|
||||
|
||||
</p>
|
||||
<b>Examples:</b><div class="pbr"><pre class="d_code"> <span class="d_comment">//node is a Node that contains integer 42
|
||||
</span> <span class="d_keyword">assert</span>(node == 42);
|
||||
<span class="d_keyword">assert</span>(node == <span class="d_string">"42"</span>);
|
||||
<span class="d_keyword">assert</span>(node != <span class="d_string">"43"</span>);
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>rhs</td>
|
||||
<td valign=top>Variable to test equality with.</td></tr>
|
||||
</table></div>
|
||||
<b>Returns:</b><div class="pbr"><b>true</b> if equal, <b>false</b> otherwise.</div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">T <a name="get"></a><span class="ddoc_psymbol">get</span>(T)();
|
||||
</dt>
|
||||
<dd><p>Get the value of the node as specified type.
|
||||
</p>
|
||||
<p>If the specifed type does not match type in the node,
|
||||
conversion is attempted if possible.
|
||||
<br>
|
||||
|
||||
Timestamps are stored as std.datetime.SysTime.
|
||||
Binary values are decoded and stored as ubyte[].
|
||||
<br>
|
||||
|
||||
<br><b>Mapping default values:</b>
|
||||
<br>
|
||||
|
||||
<div class="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
|
||||
<a name="get"></a><span class="ddoc_psymbol">get</span> 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 expects the node to be a scalar.
|
||||
</div>
|
||||
|
||||
</p>
|
||||
<b>Examples:</b><div class="pbr">Automatic type conversion:
|
||||
<pre class="d_code"> <span class="d_comment">//node is a node that contains integer 42
|
||||
</span> <span class="d_keyword">assert</span>(node.<span class="d_psymbol">get</span>!<span class="d_keyword">int</span> == 42);
|
||||
<span class="d_keyword">assert</span>(node.<span class="d_psymbol">get</span>!string == <span class="d_string">"42"</span>);
|
||||
<span class="d_keyword">assert</span>(node.<span class="d_psymbol">get</span>!<span class="d_keyword">double</span> == 42.0);
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
<b>Returns:</b><div class="pbr">Value of the node as specified type.
|
||||
|
||||
</div>
|
||||
<b>Throws:</b><div class="pbr">NodeException if unable to convert to specified type.</div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">void <a name="getToVar"></a><span class="ddoc_psymbol">getToVar</span>(T)(out T <b>target</b>);
|
||||
</dt>
|
||||
<dd><p>Write the value of the node to target.
|
||||
</p>
|
||||
<p>If the type of target does not match type of the node,
|
||||
conversion is attempted, if possible.
|
||||
|
||||
</p>
|
||||
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>target</td>
|
||||
<td valign=top>Variable to write to.</td></tr>
|
||||
</table></div>
|
||||
<b>Throws:</b><div class="pbr">NodeException if unable to convert to specified type.</div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">@property size_t <a name="length"></a><span class="ddoc_psymbol">length</span>();
|
||||
</dt>
|
||||
<dd><p>If this is a sequence or a mapping, return its <a name="length"></a><span class="ddoc_psymbol">length</span>.
|
||||
</p>
|
||||
<p>Otherwise, throw NodeException.
|
||||
|
||||
</p>
|
||||
<b>Returns:</b><div class="pbr">Number of elements in a sequence or key-value pairs in a mapping.
|
||||
|
||||
</div>
|
||||
<b>Throws:</b><div class="pbr">NodeException if this is not a sequence nor a mapping.</div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">Node <a name="opIndex"></a><span class="ddoc_psymbol">opIndex</span>(T)(in T <b>index</b>);
|
||||
</dt>
|
||||
<dd><p>Get the element with specified index.
|
||||
</p>
|
||||
<p>If the node is a sequence, index must be integral.
|
||||
<br>
|
||||
|
||||
If the node is a mapping, return the value corresponding to the first
|
||||
key equal to index, even after conversion. I.e; node["12"] will
|
||||
return value of the first key that equals "12", even if it's an integer.
|
||||
|
||||
</p>
|
||||
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>index</td>
|
||||
<td valign=top>Index to use.</td></tr>
|
||||
</table></div>
|
||||
<b>Returns:</b><div class="pbr">Value corresponding to the index.
|
||||
|
||||
</div>
|
||||
<b>Throws:</b><div class="pbr">NodeException if the index could not be found.</div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">int <a name="opApply"></a><span class="ddoc_psymbol">opApply</span>(T)(int delegate(ref T) <b>dg</b>);
|
||||
</dt>
|
||||
<dd><p>Iterate over a sequence, getting each element as T.
|
||||
</p>
|
||||
<p>If T is Node, simply iterate over the nodes in the sequence.
|
||||
Otherwise, convert each node to T during iteration.
|
||||
|
||||
</p>
|
||||
<b>Throws:</b><div class="pbr">NodeException if the node is not a sequence or an
|
||||
element could not be converted to specified type.</div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">int <a name="opApply"></a><span class="ddoc_psymbol">opApply</span>(K, V)(int delegate(ref K, ref V) <b>dg</b>);
|
||||
</dt>
|
||||
<dd><p>Iterate over a mapping, getting each key/value as K/V.
|
||||
</p>
|
||||
<p>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.
|
||||
|
||||
</p>
|
||||
<b>Throws:</b><div class="pbr">NodeException if the node is not a mapping or an
|
||||
element could not be converted to specified type.</div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">alias <a name="isInt"></a><span class="ddoc_psymbol">isInt</span>;
|
||||
</dt>
|
||||
<dd><p>Is the value an integer of some kind?</p>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">alias <a name="isFloat"></a><span class="ddoc_psymbol">isFloat</span>;
|
||||
</dt>
|
||||
<dd><p>Is the value a floating point number of some kind?</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="copyright">
|
||||
Copyright © Ferdinand Majerech 2011. Based on <a href="http://www.pyyaml.org">PyYAML</a> by Kirill Simonov. |
|
||||
Page generated by Autodoc and <a href="http://www.digitalmars.com/d/2.0/ddoc.html">Ddoc</a>.
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
99
doc/html/api/dyaml.resolver.html
Normal file
|
@ -0,0 +1,99 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" >
|
||||
<title>dyaml.resolver - D:YAML 0.1 API documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css">
|
||||
</head>
|
||||
|
||||
<body><div id="top">
|
||||
<div id="header">
|
||||
<img id="logo" alt="D:YAML logo" src="images/logo.png"><a id="main-heading" href="index.html">D:YAML 0.1 API documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="navigation">
|
||||
<div class="navblock">
|
||||
<div id="toctop">
|
||||
<ul><li><a href="../index.html">Documentation home</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navblock">
|
||||
<ul><li><a href="index.html">Main page</a></li>
|
||||
<li><a href="dyaml.constructor.html">dyaml.constructor</a></li>
|
||||
<li><a href="dyaml.exception.html">dyaml.exception</a></li>
|
||||
<li><a href="dyaml.loader.html">dyaml.loader</a></li>
|
||||
<li><a href="dyaml.node.html">dyaml.node</a></li>
|
||||
<li><a href="dyaml.resolver.html">dyaml.resolver</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<h1>dyaml.resolver</h1>
|
||||
<!-- Generated by Ddoc from dyaml/resolver.d -->
|
||||
<p>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
|
||||
<a href="../tutorials/custom_types.html">here</a>.
|
||||
</p>
|
||||
<p>Code based on <a href="http://www.pyyaml.org">PyYAML</a>.</p>
|
||||
|
||||
<dl><dt class="d_decl">class <a name="Resolver"></a><span class="ddoc_psymbol">Resolver</span>;
|
||||
</dt>
|
||||
<dd><p>Resolves YAML tags (data types).
|
||||
</p>
|
||||
<p>Can be used to implicitly resolve custom data types of scalar values.</p>
|
||||
|
||||
<dl><dt class="d_decl">this(in bool <b>defaultImplicitResolvers</b> = true);
|
||||
</dt>
|
||||
<dd><p>Construct a Resolver.
|
||||
</p>
|
||||
<p>If you don't want to implicitly resolve default YAML tags/data types,
|
||||
you can use <b>defaultImplicitResolvers</b> to disable default resolvers.
|
||||
|
||||
</p>
|
||||
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>bool <b>defaultImplicitResolvers</b></td>
|
||||
<td valign=top>Use default YAML implicit resolvers?</td></tr>
|
||||
</table></div>
|
||||
|
||||
</dd>
|
||||
<dt class="d_decl">void <a name="addImplicitResolver"></a><span class="ddoc_psymbol">addImplicitResolver</span>(string <b>tag</b>, Regex!(char) <b>regexp</b>, in string <b>first</b>);
|
||||
</dt>
|
||||
<dd><p>Add an implicit scalar resolver.
|
||||
</p>
|
||||
<p>If a scalar matches <b>regexp</b> and starts with one of the characters in <b>first</b>,
|
||||
its tag is set to <b>tag</b>. If the scalar matches more than one resolver
|
||||
regular expression, resolvers added first override those added later.
|
||||
Default resolvers override any user specified resolvers.
|
||||
<br>
|
||||
|
||||
If a scalar is not resolved to anything, it is assigned the default
|
||||
YAML tag for strings.
|
||||
|
||||
</p>
|
||||
<b>Parameters:</b><div class="pbr"><table class=parms><tr><td valign=top>string <b>tag</b></td>
|
||||
<td valign=top>Tag to resolve to.</td></tr>
|
||||
<tr><td valign=top>Regex!(char) <b>regexp</b></td>
|
||||
<td valign=top>Regular expression the scalar must match to have this tag.</td></tr>
|
||||
<tr><td valign=top>string <b>first</b></td>
|
||||
<td valign=top>String of possible starting characters of the scalar.</td></tr>
|
||||
</table></div>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="copyright">
|
||||
Copyright © Ferdinand Majerech 2011. Based on <a href="http://www.pyyaml.org">PyYAML</a> by Kirill Simonov. |
|
||||
Page generated by Autodoc and <a href="http://www.digitalmars.com/d/2.0/ddoc.html">Ddoc</a>.
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
BIN
doc/html/api/images/logo.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
61
doc/html/api/index.html
Normal file
|
@ -0,0 +1,61 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" >
|
||||
<title>D:YAML 0.1 API documentation - D:YAML 0.1 API documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css">
|
||||
</head>
|
||||
|
||||
<body><div id="top">
|
||||
<div id="header">
|
||||
<img id="logo" alt="D:YAML logo" src="images/logo.png"><a id="main-heading" href="index.html">D:YAML 0.1 API documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="navigation">
|
||||
<div class="navblock">
|
||||
<div id="toctop">
|
||||
<ul><li><a href="../index.html">Documentation home</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navblock">
|
||||
<ul><li><a href="index.html">Main page</a></li>
|
||||
<li><a href="dyaml.constructor.html">dyaml.constructor</a></li>
|
||||
<li><a href="dyaml.exception.html">dyaml.exception</a></li>
|
||||
<li><a href="dyaml.loader.html">dyaml.loader</a></li>
|
||||
<li><a href="dyaml.node.html">dyaml.node</a></li>
|
||||
<li><a href="dyaml.resolver.html">dyaml.resolver</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<h1>D:YAML 0.1 API documentation</h1>
|
||||
<!-- Generated by Ddoc from doc/html/api/index.dd -->
|
||||
|
||||
|
||||
<p>This is the complete API documentation for D:YAML. It describes all classes,
|
||||
methods and global functions provided by the library. This is not the best place
|
||||
to start learning how to use D:YAML. Rather, it should serve as a reference when
|
||||
you need detailed information about every bit of D:YAML functionality. You can
|
||||
find more introductory material in D:YAML <a href="../index.html">tutorials</a>.
|
||||
</p>
|
||||
|
||||
<p>In this API documentation, each D:YAML module is documented separately. However,
|
||||
to use D:YAML, you don't need to import these modules. All you need to do is
|
||||
import the <i>yaml</i> module, which will import all needed modules.
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div id="copyright">
|
||||
Copyright © Ferdinand Majerech 2011. Based on <a href="http://www.pyyaml.org">PyYAML</a> by Kirill Simonov. |
|
||||
Page generated by Autodoc and <a href="http://www.digitalmars.com/d/2.0/ddoc.html">Ddoc</a>.
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
150
doc/html/articles/spec_differences.html
Normal file
|
@ -0,0 +1,150 @@
|
|||
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>Differences between D:YAML and the YAML specification — D:YAML v0.1 documentation</title>
|
||||
<link rel="stylesheet" href="../_static/default.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '../',
|
||||
VERSION: '0.1',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="../_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="../_static/underscore.js"></script>
|
||||
<script type="text/javascript" src="../_static/doctools.js"></script>
|
||||
<link rel="top" title="D:YAML v0.1 documentation" href="../index.html" />
|
||||
<link rel="prev" title="YAML syntax" href="../tutorials/yaml_syntax.html" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../tutorials/yaml_syntax.html" title="YAML syntax"
|
||||
accesskey="P">previous</a></li>
|
||||
<li><a href="../index.html">D:YAML v0.1 documentation</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body">
|
||||
|
||||
<div class="section" id="differences-between-d-yaml-and-the-yaml-specification">
|
||||
<h1>Differences between D:YAML and the YAML specification<a class="headerlink" href="#differences-between-d-yaml-and-the-yaml-specification" title="Permalink to this headline">¶</a></h1>
|
||||
<p>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.</p>
|
||||
<p>Still, D:YAML tries to be as close to the specification as possible. D:YAML 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).</p>
|
||||
<div class="section" id="list-of-known-differences">
|
||||
<h2>List of known differences:<a class="headerlink" href="#list-of-known-differences" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Differences that can cause valid YAML documents not to load:</p>
|
||||
<ul>
|
||||
<li><p class="first">At the moment, all mappings in the internal representation are ordered,
|
||||
and a comparison for equality between equal mappings with differing order
|
||||
will return false. This will be fixed once Phobos has a usable map type or
|
||||
D associative arrays work with variants.</p>
|
||||
</li>
|
||||
<li><p class="first">No support for byte order marks and multiple Unicode encodings in a stream.</p>
|
||||
</li>
|
||||
<li><p class="first">Plain scalars in flow context cannot contain <tt class="docutils literal"><span class="pre">,</span></tt>, <tt class="docutils literal"><span class="pre">:</span></tt> and <tt class="docutils literal"><span class="pre">?</span></tt>.
|
||||
This might change with <tt class="docutils literal"><span class="pre">:</span></tt> in the future.
|
||||
See <a class="reference external" href="http://pyyaml.org/wiki/YAMLColonInFlowContext">http://pyyaml.org/wiki/YAMLColonInFlowContext</a> for details.</p>
|
||||
</li>
|
||||
<li><p class="first">The specification does not restrict characters for anchors and
|
||||
aliases. This may lead to problems, for instance, the document:</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="p-Indicator">[</span> <span class="nv">*alias</span><span class="p-Indicator">,</span> <span class="nv">value</span> <span class="p-Indicator">]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>can be interpteted in two ways, as:</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="p-Indicator">[</span> <span class="s">"value"</span> <span class="p-Indicator">]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>and:</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="p-Indicator">[</span> <span class="nv">*alias</span> <span class="p-Indicator">,</span> <span class="s">"value"</span> <span class="p-Indicator">]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Therefore we restrict aliases and anchors to ASCII alphanumeric characters.</p>
|
||||
</li>
|
||||
<li><p class="first">The specification is confusing about tabs in plain scalars. We don’t use tabs
|
||||
in plain scalars at all.</p>
|
||||
</li>
|
||||
<li><p class="first">There is no support for recursive data structures in DYAML.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Other differences:</p>
|
||||
<ul>
|
||||
<li><p class="first">Indentation is ignored in the flow context, which is less restrictive than the
|
||||
specification. This allows code such as:</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">key</span><span class="p-Indicator">:</span> <span class="p-Indicator">{</span>
|
||||
<span class="p-Indicator">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</li>
|
||||
<li><p class="first">Indentation rules for quoted scalars are loosed: They don’t need to adhere
|
||||
indentation as <tt class="docutils literal"><span class="pre">"</span></tt> and <tt class="docutils literal"><span class="pre">'</span></tt> clearly mark the beginning and the end of them.</p>
|
||||
</li>
|
||||
<li><p class="first">We allow <tt class="docutils literal"><span class="pre">_</span></tt> in tag handles.</p>
|
||||
</li>
|
||||
<li><p class="first">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.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../index.html">
|
||||
<img class="logo" src="../_static/logo210.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<h3><a href="../index.html">Table Of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Differences between D:YAML and the YAML specification</a><ul>
|
||||
<li><a class="reference internal" href="#list-of-known-differences">List of known differences:</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../tutorials/yaml_syntax.html" title="YAML syntax"
|
||||
>previous</a></li>
|
||||
<li><a href="../index.html">D:YAML v0.1 documentation</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer">
|
||||
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
||||
Last updated on Aug 16, 2011.
|
||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
110
doc/html/index.html
Normal file
|
@ -0,0 +1,110 @@
|
|||
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>Welcome to D:YAML documentation! — D:YAML v0.1 documentation</title>
|
||||
<link rel="stylesheet" href="_static/default.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '',
|
||||
VERSION: '0.1',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="_static/underscore.js"></script>
|
||||
<script type="text/javascript" src="_static/doctools.js"></script>
|
||||
<link rel="top" title="D:YAML v0.1 documentation" href="#" />
|
||||
<link rel="next" title="Getting started" href="tutorials/getting_started.html" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="tutorials/getting_started.html" title="Getting started"
|
||||
accesskey="N">next</a></li>
|
||||
<li><a href="#">D:YAML v0.1 documentation</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body">
|
||||
|
||||
<div class="section" id="welcome-to-d-yaml-documentation">
|
||||
<h1>Welcome to D:YAML documentation!<a class="headerlink" href="#welcome-to-d-yaml-documentation" title="Permalink to this headline">¶</a></h1>
|
||||
<p><a class="reference external" href="api/index.html">API Documentation</a></p>
|
||||
<p>Tutorials:</p>
|
||||
<div class="toctree-wrapper compound">
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="tutorials/getting_started.html">Getting started</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting_started.html#setting-up">Setting up</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorials/getting_started.html#your-first-d-yaml-project">Your first D:YAML project</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="tutorials/custom_types.html">Custom YAML data types</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorials/custom_types.html#constructor">Constructor</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorials/custom_types.html#resolver">Resolver</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="tutorials/yaml_syntax.html">YAML syntax</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorials/yaml_syntax.html#documents">Documents</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorials/yaml_syntax.html#sequences">Sequences</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorials/yaml_syntax.html#mappings">Mappings</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorials/yaml_syntax.html#scalars">Scalars</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorials/yaml_syntax.html#anchors-and-aliases">Anchors and aliases</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="tutorials/yaml_syntax.html#tags">Tags</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>Articles:</p>
|
||||
<div class="toctree-wrapper compound">
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="articles/spec_differences.html">Differences between D:YAML and the YAML specification</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="articles/spec_differences.html#list-of-known-differences">List of known differences:</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="#">
|
||||
<img class="logo" src="_static/logo210.png" alt="Logo"/>
|
||||
</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="tutorials/getting_started.html" title="Getting started"
|
||||
>next</a></li>
|
||||
<li><a href="#">D:YAML v0.1 documentation</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer">
|
||||
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
||||
Last updated on Aug 16, 2011.
|
||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
BIN
doc/html/objects.inv
Normal file
94
doc/html/search.html
Normal file
|
@ -0,0 +1,94 @@
|
|||
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>Search — D:YAML v0.1 documentation</title>
|
||||
<link rel="stylesheet" href="_static/default.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '',
|
||||
VERSION: '0.1',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="_static/underscore.js"></script>
|
||||
<script type="text/javascript" src="_static/doctools.js"></script>
|
||||
<script type="text/javascript" src="_static/searchtools.js"></script>
|
||||
<link rel="top" title="D:YAML v0.1 documentation" href="index.html" />
|
||||
<script type="text/javascript">
|
||||
jQuery(function() { Search.loadIndex("searchindex.js"); });
|
||||
</script>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="index.html">D:YAML v0.1 documentation</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body">
|
||||
|
||||
<h1 id="search-documentation">Search</h1>
|
||||
<div id="fallback" class="admonition warning">
|
||||
<script type="text/javascript">$('#fallback').hide();</script>
|
||||
<p>
|
||||
Please activate JavaScript to enable the search
|
||||
functionality.
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
From here you can search these documents. Enter your search
|
||||
words into the box below and click "search". Note that the search
|
||||
function will automatically search for all of the words. Pages
|
||||
containing fewer words won't appear in the result list.
|
||||
</p>
|
||||
<form action="" method="get">
|
||||
<input type="text" name="q" value="" />
|
||||
<input type="submit" value="search" />
|
||||
<span id="search-progress" style="padding-left: 10px"></span>
|
||||
</form>
|
||||
|
||||
<div id="search-results">
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="index.html">
|
||||
<img class="logo" src="_static/logo210.png" alt="Logo"/>
|
||||
</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li><a href="index.html">D:YAML v0.1 documentation</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer">
|
||||
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
||||
Last updated on Aug 16, 2011.
|
||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
1
doc/html/searchindex.js
Normal file
289
doc/html/tutorials/custom_types.html
Normal file
|
@ -0,0 +1,289 @@
|
|||
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>Custom YAML data types — D:YAML v0.1 documentation</title>
|
||||
<link rel="stylesheet" href="../_static/default.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '../',
|
||||
VERSION: '0.1',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="../_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="../_static/underscore.js"></script>
|
||||
<script type="text/javascript" src="../_static/doctools.js"></script>
|
||||
<link rel="top" title="D:YAML v0.1 documentation" href="../index.html" />
|
||||
<link rel="next" title="YAML syntax" href="yaml_syntax.html" />
|
||||
<link rel="prev" title="Getting started" href="getting_started.html" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="yaml_syntax.html" title="YAML syntax"
|
||||
accesskey="N">next</a></li>
|
||||
<li class="right" >
|
||||
<a href="getting_started.html" title="Getting started"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li><a href="../index.html">D:YAML v0.1 documentation</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body">
|
||||
|
||||
<div class="section" id="custom-yaml-data-types">
|
||||
<h1>Custom YAML data types<a class="headerlink" href="#custom-yaml-data-types" title="Permalink to this headline">¶</a></h1>
|
||||
<p>Often you will want to serialize complex data types such as classes. You can use
|
||||
functions to process nodes; e.g. a mapping containing class data members indexed
|
||||
by name. Alternatively, YAML supports custom data types using identifiers called
|
||||
<em>tags</em>. That is the topic of this tutorial.</p>
|
||||
<p>Each YAML node has a tag specifying its type. For instance: strings use the tag
|
||||
<tt class="docutils literal"><span class="pre">tag:yaml.org,2002:str</span></tt>. Tags of most default types are <em>implicitly resolved</em>
|
||||
during parsing, so you don’t need to specify tag for each float, integer, etc.
|
||||
It is also possible to implicitly resolve custom tags, as we will show later.</p>
|
||||
<div class="section" id="constructor">
|
||||
<h2>Constructor<a class="headerlink" href="#constructor" title="Permalink to this headline">¶</a></h2>
|
||||
<p>D:YAML uses the <em>Constructor</em> class to process each node to hold data type
|
||||
corresponding to its tag. <em>Constructor</em> stores a function for each supported
|
||||
tag to process it. These functions can be supplied by the user using the
|
||||
<em>addConstructor()</em> method. <em>Constructor</em> is then passed to <em>Loader</em>, which will
|
||||
parse YAML input.</p>
|
||||
<p>We will implement support for an RGB color type. It is implemented as the
|
||||
following struct:</p>
|
||||
<div class="highlight-d"><div class="highlight"><pre><span class="k">struct</span> <span class="n">Color</span>
|
||||
<span class="p">{</span>
|
||||
<span class="kt">ubyte</span> <span class="n">red</span><span class="p">;</span>
|
||||
<span class="kt">ubyte</span> <span class="n">green</span><span class="p">;</span>
|
||||
<span class="kt">ubyte</span> <span class="n">blue</span><span class="p">;</span>
|
||||
<span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>First, we need a function to construct our data type. It must take two <em>Mark</em>
|
||||
structs, which store position of the node in the file, and either a <em>string</em>, an
|
||||
array of <em>Node</em> or of <em>Node.Pair</em>, depending on whether we’re constructing our
|
||||
value from a scalar, sequence, or mapping, respectively. In this tutorial, we
|
||||
have functions to construct a color from a scalar, using HTML-like format,
|
||||
RRGGBB, or from a mapping, where we use the following format:
|
||||
{r:RRR, g:GGG, b:BBB} . Code of these functions:</p>
|
||||
<div class="highlight-d"><div class="highlight"><pre><span class="n">Color</span> <span class="n">constructColorScalar</span><span class="p">(</span><span class="n">Mark</span> <span class="n">start</span><span class="p">,</span> <span class="n">Mark</span> <span class="n">end</span><span class="p">,</span> <span class="nb">string</span> <span class="n">value</span><span class="p">)</span>
|
||||
<span class="p">{</span>
|
||||
<span class="k">if</span><span class="p">(</span><span class="n">value</span><span class="p">.</span><span class="n">length</span> <span class="p">!=</span> <span class="mi">6</span><span class="p">)</span>
|
||||
<span class="p">{</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="n">ConstructorException</span><span class="p">(</span><span class="s">"Invalid color: "</span> <span class="p">~</span> <span class="n">value</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">end</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
<span class="c1">//We don't need to check for uppercase chars this way.</span>
|
||||
<span class="n">value</span> <span class="p">=</span> <span class="n">value</span><span class="p">.</span><span class="n">toLower</span><span class="p">();</span>
|
||||
|
||||
<span class="c1">//Get value of a hex digit.</span>
|
||||
<span class="kt">uint</span> <span class="n">hex</span><span class="p">(</span><span class="kt">char</span> <span class="n">c</span><span class="p">)</span>
|
||||
<span class="p">{</span>
|
||||
<span class="k">if</span><span class="p">(!</span><span class="n">std</span><span class="p">.</span><span class="n">ascii</span><span class="p">.</span><span class="n">isHexDigit</span><span class="p">(</span><span class="n">c</span><span class="p">))</span>
|
||||
<span class="p">{</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="n">ConstructorException</span><span class="p">(</span><span class="s">"Invalid color: "</span> <span class="p">~</span> <span class="n">value</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">end</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="k">if</span><span class="p">(</span><span class="n">std</span><span class="p">.</span><span class="n">ascii</span><span class="p">.</span><span class="n">isDigit</span><span class="p">(</span><span class="n">c</span><span class="p">))</span>
|
||||
<span class="p">{</span>
|
||||
<span class="k">return</span> <span class="n">c</span> <span class="p">-</span> <span class="sc">'0'</span><span class="p">;</span>
|
||||
<span class="p">}</span>
|
||||
<span class="k">return</span> <span class="n">c</span> <span class="p">-</span> <span class="sc">'a'</span> <span class="p">+</span> <span class="mi">10</span><span class="p">;</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="n">Color</span> <span class="n">result</span><span class="p">;</span>
|
||||
<span class="n">result</span><span class="p">.</span><span class="n">red</span> <span class="p">=</span> <span class="k">cast</span><span class="p">(</span><span class="kt">ubyte</span><span class="p">)(</span><span class="mi">16</span> <span class="p">*</span> <span class="n">hex</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="p">+</span> <span class="n">hex</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="mi">1</span><span class="p">]));</span>
|
||||
<span class="n">result</span><span class="p">.</span><span class="n">green</span> <span class="p">=</span> <span class="k">cast</span><span class="p">(</span><span class="kt">ubyte</span><span class="p">)(</span><span class="mi">16</span> <span class="p">*</span> <span class="n">hex</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span> <span class="p">+</span> <span class="n">hex</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="mi">3</span><span class="p">]));</span>
|
||||
<span class="n">result</span><span class="p">.</span><span class="n">blue</span> <span class="p">=</span> <span class="k">cast</span><span class="p">(</span><span class="kt">ubyte</span><span class="p">)(</span><span class="mi">16</span> <span class="p">*</span> <span class="n">hex</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="mi">4</span><span class="p">])</span> <span class="p">+</span> <span class="n">hex</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="mi">5</span><span class="p">]));</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">result</span><span class="p">;</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="n">Color</span> <span class="n">constructColorMapping</span><span class="p">(</span><span class="n">Mark</span> <span class="n">start</span><span class="p">,</span> <span class="n">Mark</span> <span class="n">end</span><span class="p">,</span> <span class="n">Node</span><span class="p">.</span><span class="n">Pair</span><span class="p">[]</span> <span class="n">pairs</span><span class="p">)</span>
|
||||
<span class="p">{</span>
|
||||
<span class="kt">int</span> <span class="n">r</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="n">b</span><span class="p">;</span>
|
||||
<span class="n">r</span> <span class="p">=</span> <span class="n">g</span> <span class="p">=</span> <span class="n">b</span> <span class="p">=</span> <span class="p">-</span><span class="mi">1</span><span class="p">;</span>
|
||||
<span class="kt">bool</span> <span class="n">error</span> <span class="p">=</span> <span class="n">pairs</span><span class="p">.</span><span class="n">length</span> <span class="p">!=</span> <span class="mi">3</span><span class="p">;</span>
|
||||
|
||||
<span class="k">foreach</span><span class="p">(</span><span class="k">ref</span> <span class="n">pair</span><span class="p">;</span> <span class="n">pairs</span><span class="p">)</span>
|
||||
<span class="p">{</span>
|
||||
<span class="c1">//Key might not be a string, and value might not be an int,</span>
|
||||
<span class="c1">//so we need to check for that</span>
|
||||
<span class="k">try</span>
|
||||
<span class="p">{</span>
|
||||
<span class="k">switch</span><span class="p">(</span><span class="n">pair</span><span class="p">.</span><span class="n">key</span><span class="p">.</span><span class="n">get</span><span class="p">!</span><span class="nb">string</span><span class="p">)</span>
|
||||
<span class="p">{</span>
|
||||
<span class="k">case</span> <span class="s">"r"</span><span class="p">:</span> <span class="n">r</span> <span class="p">=</span> <span class="n">pair</span><span class="p">.</span><span class="n">value</span><span class="p">.</span><span class="n">get</span><span class="p">!</span><span class="kt">int</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span>
|
||||
<span class="k">case</span> <span class="s">"g"</span><span class="p">:</span> <span class="n">g</span> <span class="p">=</span> <span class="n">pair</span><span class="p">.</span><span class="n">value</span><span class="p">.</span><span class="n">get</span><span class="p">!</span><span class="kt">int</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span>
|
||||
<span class="k">case</span> <span class="s">"b"</span><span class="p">:</span> <span class="n">b</span> <span class="p">=</span> <span class="n">pair</span><span class="p">.</span><span class="n">value</span><span class="p">.</span><span class="n">get</span><span class="p">!</span><span class="kt">int</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span>
|
||||
<span class="k">default</span><span class="p">:</span> <span class="n">error</span> <span class="p">=</span> <span class="kc">true</span><span class="p">;</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
<span class="k">catch</span><span class="p">(</span><span class="n">NodeException</span> <span class="n">e</span><span class="p">)</span>
|
||||
<span class="p">{</span>
|
||||
<span class="n">error</span> <span class="p">=</span> <span class="kc">true</span><span class="p">;</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="k">if</span><span class="p">(</span><span class="n">error</span> <span class="p">||</span> <span class="n">r</span> <span class="p"><</span> <span class="mi">0</span> <span class="p">||</span> <span class="n">r</span> <span class="p">></span> <span class="mi">255</span> <span class="p">||</span> <span class="n">g</span> <span class="p"><</span> <span class="mi">0</span> <span class="p">||</span> <span class="n">g</span> <span class="p">></span> <span class="mi">255</span> <span class="p">||</span> <span class="n">b</span> <span class="p"><</span> <span class="mi">0</span> <span class="p">||</span> <span class="n">b</span> <span class="p">></span> <span class="mi">255</span><span class="p">)</span>
|
||||
<span class="p">{</span>
|
||||
<span class="k">throw</span> <span class="k">new</span> <span class="n">ConstructorException</span><span class="p">(</span><span class="s">"Invalid color"</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">end</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">Color</span><span class="p">(</span><span class="k">cast</span><span class="p">(</span><span class="kt">ubyte</span><span class="p">)</span><span class="n">r</span><span class="p">,</span> <span class="k">cast</span><span class="p">(</span><span class="kt">ubyte</span><span class="p">)</span><span class="n">g</span><span class="p">,</span> <span class="k">cast</span><span class="p">(</span><span class="kt">ubyte</span><span class="p">)</span><span class="n">b</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Next, we need some YAML code using our new tag. Create a file called input.yaml
|
||||
with the following contents:</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">scalar-red</span><span class="p-Indicator">:</span> <span class="kt">!color</span> <span class="l-Scalar-Plain">FF0000</span>
|
||||
<span class="l-Scalar-Plain">scalar-orange</span><span class="p-Indicator">:</span> <span class="kt">!color</span> <span class="l-Scalar-Plain">FFFF00</span>
|
||||
<span class="l-Scalar-Plain">mapping-red</span><span class="p-Indicator">:</span> <span class="kt">!color-mapping</span> <span class="p-Indicator">{</span><span class="nv">r</span><span class="p-Indicator">:</span> <span class="nv">255</span><span class="p-Indicator">,</span> <span class="nv">g</span><span class="p-Indicator">:</span> <span class="nv">0</span><span class="p-Indicator">,</span> <span class="nv">b</span><span class="p-Indicator">:</span> <span class="nv">0</span><span class="p-Indicator">}</span>
|
||||
<span class="l-Scalar-Plain">mapping-orange</span><span class="p-Indicator">:</span>
|
||||
<span class="kt">!color-mapping</span>
|
||||
<span class="l-Scalar-Plain">r</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">255</span>
|
||||
<span class="l-Scalar-Plain">g</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">255</span>
|
||||
<span class="l-Scalar-Plain">b</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">0</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can see that we’re using tag <tt class="docutils literal"><span class="pre">!color</span></tt> for scalar colors, and
|
||||
<tt class="docutils literal"><span class="pre">!color-mapping</span></tt> for colors expressed as mappings.</p>
|
||||
<p>Finally, the code to put it all together:</p>
|
||||
<div class="highlight-d"><div class="highlight"><pre><span class="kt">void</span> <span class="n">main</span><span class="p">()</span>
|
||||
<span class="p">{</span>
|
||||
<span class="k">auto</span> <span class="n">red</span> <span class="p">=</span> <span class="n">Color</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
|
||||
<span class="k">auto</span> <span class="n">orange</span> <span class="p">=</span> <span class="n">Color</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
|
||||
|
||||
<span class="k">try</span>
|
||||
<span class="p">{</span>
|
||||
<span class="k">auto</span> <span class="n">constructor</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Constructor</span><span class="p">;</span>
|
||||
<span class="c1">//both functions handle the same tag, but one handles scalar, one mapping.</span>
|
||||
<span class="n">constructor</span><span class="p">.</span><span class="n">addConstructor</span><span class="p">(</span><span class="s">"!color"</span><span class="p">,</span> <span class="p">&</span><span class="n">constructColorScalar</span><span class="p">);</span>
|
||||
<span class="n">constructor</span><span class="p">.</span><span class="n">addConstructor</span><span class="p">(</span><span class="s">"!color-mapping"</span><span class="p">,</span> <span class="p">&</span><span class="n">constructColorMapping</span><span class="p">);</span>
|
||||
|
||||
<span class="k">auto</span> <span class="n">loader</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Loader</span><span class="p">(</span><span class="s">"input.yaml"</span><span class="p">,</span> <span class="n">constructor</span><span class="p">,</span> <span class="k">new</span> <span class="n">Resolver</span><span class="p">);</span>
|
||||
|
||||
<span class="k">auto</span> <span class="n">root</span> <span class="p">=</span> <span class="n">loader</span><span class="p">.</span><span class="n">loadSingleDocument</span><span class="p">();</span>
|
||||
|
||||
<span class="k">if</span><span class="p">(</span><span class="n">root</span><span class="p">[</span><span class="s">"scalar-red"</span><span class="p">].</span><span class="n">get</span><span class="p">!</span><span class="n">Color</span> <span class="p">==</span> <span class="n">red</span> <span class="p">&&</span>
|
||||
<span class="n">root</span><span class="p">[</span><span class="s">"mapping-red"</span><span class="p">].</span><span class="n">get</span><span class="p">!</span><span class="n">Color</span> <span class="p">==</span> <span class="n">red</span> <span class="p">&&</span>
|
||||
<span class="n">root</span><span class="p">[</span><span class="s">"scalar-orange"</span><span class="p">].</span><span class="n">get</span><span class="p">!</span><span class="n">Color</span> <span class="p">==</span> <span class="n">orange</span> <span class="p">&&</span>
|
||||
<span class="n">root</span><span class="p">[</span><span class="s">"mapping-orange"</span><span class="p">].</span><span class="n">get</span><span class="p">!</span><span class="n">Color</span> <span class="p">==</span> <span class="n">orange</span><span class="p">)</span>
|
||||
<span class="p">{</span>
|
||||
<span class="n">writeln</span><span class="p">(</span><span class="s">"SUCCESS"</span><span class="p">);</span>
|
||||
<span class="k">return</span><span class="p">;</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
<span class="k">catch</span><span class="p">(</span><span class="n">YAMLException</span> <span class="n">e</span><span class="p">)</span>
|
||||
<span class="p">{</span>
|
||||
<span class="n">writeln</span><span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">msg</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="n">writeln</span><span class="p">(</span><span class="s">"FAILURE"</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>First, we create a <em>Constructor</em> and pass functions to handle the <tt class="docutils literal"><span class="pre">!color</span></tt>
|
||||
and <tt class="docutils literal"><span class="pre">!color-mapping</span></tt> tag. We construct a <em>Loader</em> using the <em>Constructor</em>.
|
||||
We also need a <em>Resolver</em>, but for now we just default-construct it. We then
|
||||
load the YAML document, and finally, read the colors using <em>get()</em> method to
|
||||
test if they were loaded as expected.</p>
|
||||
<p>You can find the source code for what we’ve done so far in the
|
||||
<tt class="docutils literal"><span class="pre">examples/constructor</span></tt> directory in the D:YAML package.</p>
|
||||
</div>
|
||||
<div class="section" id="resolver">
|
||||
<h2>Resolver<a class="headerlink" href="#resolver" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Specifying tag for every color value can be tedious. D:YAML can implicitly
|
||||
resolve tag of a scalar using a regular expression. This is how default types,
|
||||
e.g. int, are resolved. We will use the <em>Resolver</em> class to add implicit tag
|
||||
resolution for the Color data type (in its scalar form).</p>
|
||||
<p>We use the <em>addImplicitResolver</em> method of <em>Resolver</em>, passing the tag, regular
|
||||
expression the value must match to resolve to this tag, and a string of possible
|
||||
starting characters of the value. Then we pass the <em>Resolver</em> to the constructor
|
||||
of <em>Loader</em>.</p>
|
||||
<p>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.</p>
|
||||
<p>Add this to your code to add implicit resolution of <tt class="docutils literal"><span class="pre">!color</span></tt>.</p>
|
||||
<div class="highlight-d"><div class="highlight"><pre><span class="c1">//code from the previous example...</span>
|
||||
|
||||
<span class="k">auto</span> <span class="n">resolver</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Resolver</span><span class="p">;</span>
|
||||
<span class="n">resolver</span><span class="p">.</span><span class="n">addImplicitResolver</span><span class="p">(</span><span class="s">"!color"</span><span class="p">,</span> <span class="n">std</span><span class="p">.</span><span class="n">regex</span><span class="p">.</span><span class="n">regex</span><span class="p">(</span><span class="s">"[0-9a-fA-F]{6}"</span><span class="p">,</span>
|
||||
<span class="s">"0123456789abcdefABCDEF"</span><span class="p">));</span>
|
||||
|
||||
<span class="k">auto</span> <span class="n">loader</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Loader</span><span class="p">(</span><span class="s">"input.yaml"</span><span class="p">,</span> <span class="n">constructor</span><span class="p">,</span> <span class="n">resolver</span><span class="p">);</span>
|
||||
|
||||
<span class="c1">//code from the previous example...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Now, change contents of input.dyaml to this:</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">scalar-red</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">FF0000</span>
|
||||
<span class="l-Scalar-Plain">scalar-orange</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">FFFF00</span>
|
||||
<span class="l-Scalar-Plain">mapping-red</span><span class="p-Indicator">:</span> <span class="kt">!color-mapping</span> <span class="p-Indicator">{</span><span class="nv">r</span><span class="p-Indicator">:</span> <span class="nv">255</span><span class="p-Indicator">,</span> <span class="nv">g</span><span class="p-Indicator">:</span> <span class="nv">0</span><span class="p-Indicator">,</span> <span class="nv">b</span><span class="p-Indicator">:</span> <span class="nv">0</span><span class="p-Indicator">}</span>
|
||||
<span class="l-Scalar-Plain">mapping-orange</span><span class="p-Indicator">:</span>
|
||||
<span class="kt">!color-mapping</span>
|
||||
<span class="l-Scalar-Plain">r</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">255</span>
|
||||
<span class="l-Scalar-Plain">g</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">255</span>
|
||||
<span class="l-Scalar-Plain">b</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">0</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>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.</p>
|
||||
<p>You can find the complete code in the <tt class="docutils literal"><span class="pre">examples/resolver</span></tt> directory in the
|
||||
D:YAML package.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../index.html">
|
||||
<img class="logo" src="../_static/logo210.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<h3><a href="../index.html">Table Of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Custom YAML data types</a><ul>
|
||||
<li><a class="reference internal" href="#constructor">Constructor</a></li>
|
||||
<li><a class="reference internal" href="#resolver">Resolver</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="yaml_syntax.html" title="YAML syntax"
|
||||
>next</a></li>
|
||||
<li class="right" >
|
||||
<a href="getting_started.html" title="Getting started"
|
||||
>previous</a> |</li>
|
||||
<li><a href="../index.html">D:YAML v0.1 documentation</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer">
|
||||
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
||||
Last updated on Aug 16, 2011.
|
||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
231
doc/html/tutorials/getting_started.html
Normal file
|
@ -0,0 +1,231 @@
|
|||
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>Getting started — D:YAML v0.1 documentation</title>
|
||||
<link rel="stylesheet" href="../_static/default.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '../',
|
||||
VERSION: '0.1',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="../_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="../_static/underscore.js"></script>
|
||||
<script type="text/javascript" src="../_static/doctools.js"></script>
|
||||
<link rel="top" title="D:YAML v0.1 documentation" href="../index.html" />
|
||||
<link rel="next" title="Custom YAML data types" href="custom_types.html" />
|
||||
<link rel="prev" title="Welcome to D:YAML documentation!" href="../index.html" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="custom_types.html" title="Custom YAML data types"
|
||||
accesskey="N">next</a></li>
|
||||
<li class="right" >
|
||||
<a href="../index.html" title="Welcome to D:YAML documentation!"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li><a href="../index.html">D:YAML v0.1 documentation</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body">
|
||||
|
||||
<div class="section" id="getting-started">
|
||||
<h1>Getting started<a class="headerlink" href="#getting-started" title="Permalink to this headline">¶</a></h1>
|
||||
<p>Welcome to D:YAML! D:YAML is a <a class="reference external" href="http://en.wikipedia.org/wiki/YAML">YAML</a> parser
|
||||
library for the <a class="reference external" href="http://d-p-l.org">D programming language</a>. This tutorial will
|
||||
explain how to set D:YAML up and use it in your projects.</p>
|
||||
<p>This is meant to be the <strong>simplest possible</strong> introduction to D:YAML. Some of the
|
||||
information present might already be known to you. Only basic usage is covered.
|
||||
More advanced usage is described in other tutorials.</p>
|
||||
<div class="section" id="setting-up">
|
||||
<h2>Setting up<a class="headerlink" href="#setting-up" title="Permalink to this headline">¶</a></h2>
|
||||
<div class="section" id="install-the-dmd-compiler">
|
||||
<h3>Install the DMD compiler<a class="headerlink" href="#install-the-dmd-compiler" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Digital Mars D compiler, or DMD, is the most commonly used D compiler. You can
|
||||
find its newest version <a class="reference external" href="http://www.digitalmars.com/d/download.html">here</a>.
|
||||
Download the version of DMD for your operating system and install it.</p>
|
||||
<div class="admonition note">
|
||||
<p class="first admonition-title">Note</p>
|
||||
<p class="last">Other D compilers exist, such as
|
||||
<a class="reference external" href="http://bitbucket.org/goshawk/gdc/wiki/Home">GDC</a> and
|
||||
<a class="reference external" href="http://www.dsource.org/projects/ldc/">LDC</a>.
|
||||
Setting up with either one of them should be similar to DMD,
|
||||
however, at the moment they are not as up to date as DMD.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="download-and-compile-d-yaml">
|
||||
<h3>Download and compile D:YAML<a class="headerlink" href="#download-and-compile-d-yaml" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The newest version of D:YAML can be found <a class="reference external" href="TODO">here</a>. Download a source
|
||||
archive, extract it, and move to the extracted directory.</p>
|
||||
<p>D:YAML uses a modified version of the <a class="reference external" href="http://dsource.org/projects/cdc/">CDC</a>
|
||||
script for compilation. To compile D:YAML, you first need to build CDC.
|
||||
Do this by typing the following command into the console:</p>
|
||||
<div class="highlight-python"><pre>dmd cdc.d</pre>
|
||||
</div>
|
||||
<p>Now you can use CDC to compile D:YAML.
|
||||
To do this on Unix/Linux, use the following command:</p>
|
||||
<div class="highlight-python"><pre>./cdc</pre>
|
||||
</div>
|
||||
<p>On Windows:</p>
|
||||
<div class="highlight-python"><div class="highlight"><pre><span class="n">cdc</span><span class="o">.</span><span class="n">exe</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will compile the library to a file called <tt class="docutils literal"><span class="pre">libdyaml.a</span></tt> on Unix/Linux or
|
||||
<tt class="docutils literal"><span class="pre">libdyaml.lib</span></tt> on Windows.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="your-first-d-yaml-project">
|
||||
<h2>Your first D:YAML project<a class="headerlink" href="#your-first-d-yaml-project" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Create a directory for your project and in that directory, create a file called
|
||||
<tt class="docutils literal"><span class="pre">input.yaml</span></tt> with the following contents:</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">Hello World</span> <span class="p-Indicator">:</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Hello</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">World</span>
|
||||
<span class="l-Scalar-Plain">Answer</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">42</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will serve as input for our example.</p>
|
||||
<p>Now we need to parse it. Create a file called “main.d”. Paste following code
|
||||
into the file:</p>
|
||||
<div class="highlight-d"><div class="highlight"><pre><span class="k">import</span> <span class="n">std</span><span class="p">.</span><span class="n">stdio</span><span class="p">;</span>
|
||||
<span class="k">import</span> <span class="n">yaml</span><span class="p">;</span>
|
||||
|
||||
<span class="kt">void</span> <span class="n">main</span><span class="p">()</span>
|
||||
<span class="p">{</span>
|
||||
<span class="n">yaml</span><span class="p">.</span><span class="n">Node</span> <span class="n">root</span> <span class="p">=</span> <span class="n">yaml</span><span class="p">.</span><span class="n">load</span><span class="p">(</span><span class="s">"input.yaml"</span><span class="p">);</span>
|
||||
<span class="k">foreach</span><span class="p">(</span><span class="nb">string</span> <span class="n">word</span><span class="p">;</span> <span class="n">root</span><span class="p">[</span><span class="s">"Hello World"</span><span class="p">])</span>
|
||||
<span class="p">{</span>
|
||||
<span class="n">writeln</span><span class="p">(</span><span class="n">word</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
<span class="n">writeln</span><span class="p">(</span><span class="s">"The answer is "</span><span class="p">,</span> <span class="n">root</span><span class="p">[</span><span class="s">"Answer"</span><span class="p">].</span><span class="n">get</span><span class="p">!</span><span class="kt">int</span><span class="p">);</span>
|
||||
<span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="section" id="explanation-of-the-code">
|
||||
<h3>Explanation of the code<a class="headerlink" href="#explanation-of-the-code" title="Permalink to this headline">¶</a></h3>
|
||||
<p>First, we import the <em>yaml</em> module. This is the only module you need to import
|
||||
to use D:YAML - it automatically imports all needed modules.</p>
|
||||
<p>Next we load the file using the <em>yaml.load()</em> function - this loads the file as
|
||||
<strong>one</strong> YAML document and throws <em>YAMLException</em>, D:YAML exception type, if the
|
||||
file could not be parsed or does not contain exactly one document. Note that we
|
||||
don’t do any error checking here in order to keep the example as simple as
|
||||
possible.</p>
|
||||
<p><em>yaml.Node</em> 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 first, as it is a sequence, and use the
|
||||
<em>yaml.Node.get()</em> method on the second to get its value as an integer.</p>
|
||||
<p>You can iterate over a mapping or sequence as if it was an associative or normal
|
||||
array. If you try to iterate over a scalar, it will throw a <em>YAMLException</em>.</p>
|
||||
<p>You can iterate over subnodes using yaml.Node as the iterated type, or specify
|
||||
the type subnodes are expected to have. D:YAML will automatically convert
|
||||
iterated subnodes to that type if possible. Here we specify the <em>string</em> 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 <em>YAMLException</em> is thrown. For
|
||||
instance, if we specified <em>int</em> here, we would get an error, as “Hello”
|
||||
cannot be converted to an integer.</p>
|
||||
<p>The <em>yaml.Node.get()</em> method is used to get value of a scalar node as specified
|
||||
type. D:YAML will try to return the scalar as specified type, converting if
|
||||
needed, throwing <em>YAMLException</em> if not possible.</p>
|
||||
</div>
|
||||
<div class="section" id="compiling">
|
||||
<h3>Compiling<a class="headerlink" href="#compiling" title="Permalink to this headline">¶</a></h3>
|
||||
<p>To compile your project, you must give DMD the directories containing import
|
||||
modules and the library. You also need to tell it to link with D:YAML. The import
|
||||
directory should be the D:YAML package directory. You can specify it using the
|
||||
<tt class="docutils literal"><span class="pre">-I</span></tt> option of DMD. The library directory should point to where you put the
|
||||
compiled D:YAML library. On Unix/Linux you can specify it using the <tt class="docutils literal"><span class="pre">-L-L</span></tt>
|
||||
option, and link with D:YAML using the <tt class="docutils literal"><span class="pre">-L-l</span></tt> option. On Windows, the import
|
||||
directory is used as the library directory. To link with the library on Windows,
|
||||
just add the path to it relative to the current directory.</p>
|
||||
<p>For example, if you extracted D:YAML to <tt class="docutils literal"><span class="pre">/home/xxx/dyaml</span></tt> and compiled it in
|
||||
that directory, your project is in <tt class="docutils literal"><span class="pre">/home/xxx/dyaml-project</span></tt>, and you are
|
||||
currently in that directory, you can compile the project with the following
|
||||
command on Unix/Linux:</p>
|
||||
<div class="highlight-python"><pre>dmd -I../dyaml -L-L../dyaml -L-ldyaml main.d</pre>
|
||||
</div>
|
||||
<p>And the following on Windows:</p>
|
||||
<div class="highlight-python"><pre>dmd -I../dyaml ../dyaml/libdyaml.lib main.d</pre>
|
||||
</div>
|
||||
<p>This will produce an executable called <tt class="docutils literal"><span class="pre">main</span></tt> or <tt class="docutils literal"><span class="pre">main.exe</span></tt> in your
|
||||
directory. When you run it, it should produce the following output:</p>
|
||||
<div class="highlight-python"><pre>Hello
|
||||
World
|
||||
The answer is 42</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="conclusion">
|
||||
<h3>Conclusion<a class="headerlink" href="#conclusion" title="Permalink to this headline">¶</a></h3>
|
||||
<p>You should now have a basic idea about how to use D:YAML. To learn more, look at
|
||||
the <a class="reference external" href="../api/index.html">API documentation</a> and other tutorials. You can find code for this
|
||||
example in the <tt class="docutils literal"><span class="pre">example/getting_started</span></tt> directory in the package.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../index.html">
|
||||
<img class="logo" src="../_static/logo210.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<h3><a href="../index.html">Table Of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Getting started</a><ul>
|
||||
<li><a class="reference internal" href="#setting-up">Setting up</a><ul>
|
||||
<li><a class="reference internal" href="#install-the-dmd-compiler">Install the DMD compiler</a></li>
|
||||
<li><a class="reference internal" href="#download-and-compile-d-yaml">Download and compile D:YAML</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#your-first-d-yaml-project">Your first D:YAML project</a><ul>
|
||||
<li><a class="reference internal" href="#explanation-of-the-code">Explanation of the code</a></li>
|
||||
<li><a class="reference internal" href="#compiling">Compiling</a></li>
|
||||
<li><a class="reference internal" href="#conclusion">Conclusion</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="custom_types.html" title="Custom YAML data types"
|
||||
>next</a></li>
|
||||
<li class="right" >
|
||||
<a href="../index.html" title="Welcome to D:YAML documentation!"
|
||||
>previous</a> |</li>
|
||||
<li><a href="../index.html">D:YAML v0.1 documentation</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer">
|
||||
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
||||
Last updated on Aug 16, 2011.
|
||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
338
doc/html/tutorials/yaml_syntax.html
Normal file
|
@ -0,0 +1,338 @@
|
|||
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
|
||||
<title>YAML syntax — D:YAML v0.1 documentation</title>
|
||||
<link rel="stylesheet" href="../_static/default.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '../',
|
||||
VERSION: '0.1',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '.html',
|
||||
HAS_SOURCE: true
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript" src="../_static/jquery.js"></script>
|
||||
<script type="text/javascript" src="../_static/underscore.js"></script>
|
||||
<script type="text/javascript" src="../_static/doctools.js"></script>
|
||||
<link rel="top" title="D:YAML v0.1 documentation" href="../index.html" />
|
||||
<link rel="next" title="Differences between D:YAML and the YAML specification" href="../articles/spec_differences.html" />
|
||||
<link rel="prev" title="Custom YAML data types" href="custom_types.html" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../articles/spec_differences.html" title="Differences between D:YAML and the YAML specification"
|
||||
accesskey="N">next</a></li>
|
||||
<li class="right" >
|
||||
<a href="custom_types.html" title="Custom YAML data types"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li><a href="../index.html">D:YAML v0.1 documentation</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
<div class="documentwrapper">
|
||||
<div class="bodywrapper">
|
||||
<div class="body">
|
||||
|
||||
<div class="section" id="yaml-syntax">
|
||||
<h1>YAML syntax<a class="headerlink" href="#yaml-syntax" title="Permalink to this headline">¶</a></h1>
|
||||
<p>This is an introduction to the most common YAML constructs. For more detailed
|
||||
information, see <a class="reference external" href="http://pyyaml.org/wiki/PyYAMLDocumentation">PyYAML documentation</a>,
|
||||
which this article is based on,
|
||||
<a class="reference external" href="http://yaml.org/spec/1.1/#id857168">Chapter 2 of the YAML specification</a>
|
||||
or the <a class="reference external" href="http://en.wikipedia.org/wiki/YAML">Wikipedia page</a>.</p>
|
||||
<p>YAML is a data serialization format designed to be as human readable as
|
||||
possible. YAML is a recursive acronym for “YAML Ain’t Markup Language”.</p>
|
||||
<p>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, YAML 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 either depends on indentation (block context, similar to
|
||||
Python code), or nesting of brackets and braces (flow context, similar to JSON).
|
||||
YAML comments begin with <tt class="docutils literal"><span class="pre">#</span></tt> and continue until the end of line.</p>
|
||||
<div class="section" id="documents">
|
||||
<h2>Documents<a class="headerlink" href="#documents" title="Permalink to this headline">¶</a></h2>
|
||||
<p>A YAML stream consists of one or more documents starting with <tt class="docutils literal"><span class="pre">---</span></tt> and
|
||||
optionally ending with <tt class="docutils literal"><span class="pre">...</span></tt> . If there is only one document, <tt class="docutils literal"><span class="pre">---</span></tt> can be
|
||||
left out.</p>
|
||||
<p>Single document with no explicit start or end:</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Red</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Green</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Blue</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Same document with explicit start and end:</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="nn">---</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Red</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Green</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Blue</span>
|
||||
<span class="nn">...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>A stream containing multiple documents:</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="nn">---</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Red</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Green</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Blue</span>
|
||||
<span class="nn">---</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Linux</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">BSD</span>
|
||||
<span class="nn">---</span>
|
||||
<span class="l-Scalar-Plain">answer</span> <span class="p-Indicator">:</span> <span class="l-Scalar-Plain">42</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="sequences">
|
||||
<h2>Sequences<a class="headerlink" href="#sequences" title="Permalink to this headline">¶</a></h2>
|
||||
<p>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.</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="c1">#Block context</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Red</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Green</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Blue</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="c1">#Flow context</span>
|
||||
<span class="p-Indicator">[</span><span class="nv">Red</span><span class="p-Indicator">,</span> <span class="nv">Green</span><span class="p-Indicator">,</span> <span class="nv">Blue</span><span class="p-Indicator">]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="c1">#Nested</span>
|
||||
<span class="p-Indicator">-</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Red</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Green</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Blue</span>
|
||||
<span class="p-Indicator">-</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Linux</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">BSD</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="c1">#Nested flow</span>
|
||||
<span class="p-Indicator">[[</span><span class="nv">Red</span><span class="p-Indicator">,</span> <span class="nv">Green</span><span class="p-Indicator">,</span> <span class="nv">Blue</span><span class="p-Indicator">],</span> <span class="p-Indicator">[</span><span class="nv">Linux</span><span class="p-Indicator">,</span> <span class="nv">BSD</span><span class="p-Indicator">]]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="c1">#Nested in a mapping</span>
|
||||
<span class="l-Scalar-Plain">Colors</span><span class="p-Indicator">:</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Red</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Green</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Blue</span>
|
||||
<span class="l-Scalar-Plain">Operating systems</span><span class="p-Indicator">:</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">Linux</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">BSD</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="mappings">
|
||||
<h2>Mappings<a class="headerlink" href="#mappings" title="Permalink to this headline">¶</a></h2>
|
||||
<p>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:</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="c1">#Block context</span>
|
||||
<span class="l-Scalar-Plain">CPU</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Athlon</span>
|
||||
<span class="l-Scalar-Plain">GPU</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Radeon</span>
|
||||
<span class="l-Scalar-Plain">OS</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Linux</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="c1">#Flow context</span>
|
||||
<span class="p-Indicator">{</span><span class="nv">CPU</span><span class="p-Indicator">:</span> <span class="nv">Athlon</span><span class="p-Indicator">,</span> <span class="nv">GPU</span><span class="p-Indicator">:</span> <span class="nv">Radeon</span><span class="p-Indicator">,</span> <span class="nv">OS</span><span class="p-Indicator">:</span> <span class="nv">Linux</span><span class="p-Indicator">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="c1">#Nested</span>
|
||||
<span class="l-Scalar-Plain">PC</span><span class="p-Indicator">:</span>
|
||||
<span class="l-Scalar-Plain">CPU</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Athlon</span>
|
||||
<span class="l-Scalar-Plain">GPU</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Radeon</span>
|
||||
<span class="l-Scalar-Plain">OS</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Debian</span>
|
||||
<span class="l-Scalar-Plain">Phone</span><span class="p-Indicator">:</span>
|
||||
<span class="l-Scalar-Plain">CPU</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Cortex</span>
|
||||
<span class="l-Scalar-Plain">GPU</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">PowerVR</span>
|
||||
<span class="l-Scalar-Plain">OS</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Android</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="c1">#Nested flow</span>
|
||||
<span class="p-Indicator">{</span><span class="nv">PC</span><span class="p-Indicator">:</span> <span class="p-Indicator">{</span><span class="nv">CPU</span><span class="p-Indicator">:</span> <span class="nv">Athlon</span><span class="p-Indicator">,</span> <span class="nv">GPU</span><span class="p-Indicator">:</span> <span class="nv">Radeon</span><span class="p-Indicator">,</span> <span class="nv">OS</span><span class="p-Indicator">:</span> <span class="nv">Debian</span><span class="p-Indicator">},</span>
|
||||
<span class="nv">Phone</span><span class="p-Indicator">:</span> <span class="p-Indicator">{</span><span class="nv">CPU</span><span class="p-Indicator">:</span> <span class="nv">Cortex</span><span class="p-Indicator">,</span> <span class="nv">GPU</span><span class="p-Indicator">:</span> <span class="nv">PowerVR</span><span class="p-Indicator">,</span> <span class="nv">OS</span><span class="p-Indicator">:</span> <span class="nv">Android</span><span class="p-Indicator">}}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="c1">#Nested in a sequence</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">CPU</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Athlon</span>
|
||||
<span class="l-Scalar-Plain">GPU</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Radeon</span>
|
||||
<span class="l-Scalar-Plain">OS</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Debian</span>
|
||||
<span class="p-Indicator">-</span> <span class="l-Scalar-Plain">CPU</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Cortex</span>
|
||||
<span class="l-Scalar-Plain">GPU</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">PowerVR</span>
|
||||
<span class="l-Scalar-Plain">OS</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Android</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Complex keys start with question mark+space “? “.</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="c1">#Nested in a sequence</span>
|
||||
<span class="p-Indicator">?</span> <span class="p-Indicator">[</span><span class="nv">CPU</span><span class="p-Indicator">,</span> <span class="nv">GPU</span><span class="p-Indicator">]:</span> <span class="p-Indicator">[</span><span class="nv">Athlon</span><span class="p-Indicator">,</span> <span class="nv">Radeon</span><span class="p-Indicator">]</span>
|
||||
<span class="l-Scalar-Plain">OS</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Debian</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="scalars">
|
||||
<h2>Scalars<a class="headerlink" href="#scalars" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Scalars are simple values such as integers, strings, timestamps and so on.
|
||||
There are multiple scalar styles.</p>
|
||||
<p>Plain scalars use no quotes, start with the first non-space and end with the
|
||||
last non-space character:</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">scalar</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Plain scalar</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Single quoted scalars start and end with single quotes. A single quote is
|
||||
represented by a pair of single quotes ‘’.</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">scalar</span><span class="p-Indicator">:</span> <span class="s">'Single</span><span class="nv"> </span><span class="s">quoted</span><span class="nv"> </span><span class="s">scalar</span><span class="nv"> </span><span class="s">ending</span><span class="nv"> </span><span class="s">with</span><span class="nv"> </span><span class="s">some</span><span class="nv"> </span><span class="s">spaces</span><span class="nv"> </span><span class="s">'</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Double quoted scalars support C-style escape sequences.</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">scalar</span><span class="p-Indicator">:</span> <span class="s">"Double</span><span class="nv"> </span><span class="s">quoted</span><span class="nv"> </span><span class="s">scalar</span><span class="nv"> </span><span class="s">\n</span><span class="nv"> </span><span class="s">with</span><span class="nv"> </span><span class="s">some</span><span class="nv"> </span><span class="s">\\</span><span class="nv"> </span><span class="s">escape</span><span class="nv"> </span><span class="s">sequences"</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Block scalars are convenient for multi-line values. They start either with
|
||||
<tt class="docutils literal"><span class="pre">|</span></tt> or with <tt class="docutils literal"><span class="pre">></span></tt>. With <tt class="docutils literal"><span class="pre">|</span></tt>, the newlines in the scalar are preserved.
|
||||
With <tt class="docutils literal"><span class="pre">></span></tt>, the newlines between two non-empty lines are removed.</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">scalar</span><span class="p-Indicator">:</span> <span class="p-Indicator">|</span>
|
||||
<span class="no">Newlines are preserved</span>
|
||||
<span class="no">First line</span>
|
||||
<span class="no">Second line</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">scalar</span><span class="p-Indicator">:</span> <span class="p-Indicator">></span>
|
||||
<span class="no">Newlines are folded</span>
|
||||
<span class="no">This is still the first paragraph</span>
|
||||
|
||||
<span class="no">This is the second</span>
|
||||
<span class="no">paragraph</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="anchors-and-aliases">
|
||||
<h2>Anchors and aliases<a class="headerlink" href="#anchors-and-aliases" title="Permalink to this headline">¶</a></h2>
|
||||
<p>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).</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">Person</span><span class="p-Indicator">:</span> <span class="nl">&AD</span>
|
||||
<span class="l-Scalar-Plain">gender</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">male</span>
|
||||
<span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Arthur Dent</span>
|
||||
<span class="l-Scalar-Plain">Clone</span><span class="p-Indicator">:</span> <span class="nv">*AD</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="tags">
|
||||
<h2>Tags<a class="headerlink" href="#tags" title="Permalink to this headline">¶</a></h2>
|
||||
<p>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.</p>
|
||||
<p>Explicitly specified tags:</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">answer</span><span class="p-Indicator">:</span> <span class="kt">!!int</span> <span class="s">"42"</span>
|
||||
<span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="kt">!!str</span> <span class="s">"Arthur</span><span class="nv"> </span><span class="s">Dent"</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Implicit tags:</p>
|
||||
<div class="highlight-yaml"><div class="highlight"><pre><span class="l-Scalar-Plain">answer</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">42</span> <span class="c1">#int</span>
|
||||
<span class="l-Scalar-Plain">name</span><span class="p-Indicator">:</span> <span class="l-Scalar-Plain">Arthur Dent</span> <span class="c1">#string</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This table shows D types stored in <em>yaml.Node</em> default YAML tags are converted to.
|
||||
Some of these might change in the future (especially !!map and !!set).</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="58%" />
|
||||
<col width="42%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">YAML tag</th>
|
||||
<th class="head">D type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>!!null</td>
|
||||
<td>yaml.YAMLNull</td>
|
||||
</tr>
|
||||
<tr><td>!!bool</td>
|
||||
<td>bool</td>
|
||||
</tr>
|
||||
<tr><td>!!int</td>
|
||||
<td>long</td>
|
||||
</tr>
|
||||
<tr><td>!!float</td>
|
||||
<td>real</td>
|
||||
</tr>
|
||||
<tr><td>!!binary</td>
|
||||
<td>ubyte[]</td>
|
||||
</tr>
|
||||
<tr><td>!!timestamp</td>
|
||||
<td>datetime.SysTime</td>
|
||||
</tr>
|
||||
<tr><td>!!map, !!omap, !!pairs</td>
|
||||
<td>Node.Pair[]</td>
|
||||
</tr>
|
||||
<tr><td>!!seq, !!set</td>
|
||||
<td>Node[]</td>
|
||||
</tr>
|
||||
<tr><td>!!str</td>
|
||||
<td>string</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../index.html">
|
||||
<img class="logo" src="../_static/logo210.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<h3><a href="../index.html">Table Of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">YAML syntax</a><ul>
|
||||
<li><a class="reference internal" href="#documents">Documents</a></li>
|
||||
<li><a class="reference internal" href="#sequences">Sequences</a></li>
|
||||
<li><a class="reference internal" href="#mappings">Mappings</a></li>
|
||||
<li><a class="reference internal" href="#scalars">Scalars</a></li>
|
||||
<li><a class="reference internal" href="#anchors-and-aliases">Anchors and aliases</a></li>
|
||||
<li><a class="reference internal" href="#tags">Tags</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
<div class="related">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../articles/spec_differences.html" title="Differences between D:YAML and the YAML specification"
|
||||
>next</a></li>
|
||||
<li class="right" >
|
||||
<a href="custom_types.html" title="Custom YAML data types"
|
||||
>previous</a> |</li>
|
||||
<li><a href="../index.html">D:YAML v0.1 documentation</a> »</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer">
|
||||
© Copyright 2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org by Kirill Simonov.
|
||||
Last updated on Aug 16, 2011.
|
||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
139
docsrc/Makefile
Normal file
|
@ -0,0 +1,139 @@
|
|||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = ../doc
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean ddoc_html html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
################################################################################
|
||||
# DDOC GENERATION CODE
|
||||
################################################################################
|
||||
ddoc_html :
|
||||
cd ../ && ./autoddoc.py
|
||||
################################################################################
|
||||
# DDOC GENERATION CODE END
|
||||
################################################################################
|
||||
|
||||
html: ddoc_html
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/DYAML.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/DYAML.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/DYAML"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/DYAML"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
make -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
65
docsrc/articles/spec_differences.rst
Normal file
|
@ -0,0 +1,65 @@
|
|||
.. highlight:: yaml
|
||||
|
||||
=====================================================
|
||||
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. D:YAML 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:
|
||||
|
||||
* At the moment, all mappings in the internal representation are ordered,
|
||||
and a comparison for equality between equal mappings with differing order
|
||||
will return false. This will be fixed once Phobos has a usable map type or
|
||||
D associative arrays work with variants.
|
||||
* 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.
|
19
docsrc/autoddoc_index.dd
Normal file
|
@ -0,0 +1,19 @@
|
|||
Ddoc
|
||||
|
||||
$(P
|
||||
This is the complete API documentation for D:YAML. It describes all classes,
|
||||
methods and global functions provided by the library. This is not the best place
|
||||
to start learning how to use D:YAML. Rather, it should serve as a reference when
|
||||
you need detailed information about every bit of D:YAML functionality. You can
|
||||
find more introductory material in D:YAML $(LINK2 ../index.html, tutorials).
|
||||
)
|
||||
|
||||
$(P
|
||||
In this API documentation, each D:YAML module is documented separately. However,
|
||||
to use D:YAML, you don't need to import these modules. All you need to do is
|
||||
import the $(I yaml) module, which will import all needed modules.
|
||||
)
|
||||
|
||||
Macros:
|
||||
TITLE=$(PROJECT_NAME) $(PROJECT_VERSION) API documentation
|
||||
|
236
docsrc/conf.py
Normal file
|
@ -0,0 +1,236 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# D:YAML documentation build configuration file, created by
|
||||
# sphinx-quickstart on Sun Jul 24 15:16:35 2011.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = []
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'D:YAML'
|
||||
copyright = (u'2011, Ferdinand Majerech. Based on PyYAML http://www.pyyaml.org '
|
||||
'by Kirill Simonov')
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.1'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'default'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
html_theme_options =\
|
||||
{
|
||||
"footerbgcolor" : "#1f252b",
|
||||
"footertextcolor" : "#ccc",
|
||||
"sidebarbgcolor" : "#1f252b",
|
||||
"sidebarlinkcolor" : "#ddd",
|
||||
"relbarbgcolor" : "#303333",
|
||||
"relbartextcolor" : "#ccc",
|
||||
"bgcolor" : "#f6f6f6",
|
||||
"textcolor" : "black",
|
||||
"linkcolor" : "#006",
|
||||
"visitedlinkcolor" : "#606",
|
||||
"headbgcolor" : "#f6f6f6",
|
||||
"headtextcolor" : "#633",
|
||||
"headlinkcolor" : "#006",
|
||||
"codebgcolor" : "fcfcfc",
|
||||
"codetextcolor" : "000066",
|
||||
"bodyfont" : "Verdana, \"Deja Vu\", \"Bitstream Vera Sans\", sans-serif",
|
||||
"headfont" : "Georgia, \"Times New Roman\", Times, serif"
|
||||
}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
html_logo = "logo210.png"
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
html_sidebars = {"**" : ["localtoc.html"]}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
html_domain_indices = False
|
||||
|
||||
# If false, no index is generated.
|
||||
html_use_index = False
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'DYAMLdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
# The paper size ('letter' or 'a4').
|
||||
#latex_paper_size = 'letter'
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#latex_font_size = '10pt'
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'DYAML.tex', u'D:YAML Documentation',
|
||||
u'Ferdinand Majerech', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#latex_preamble = ''
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'dyaml', u'D:YAML Documentation',
|
||||
[u'Ferdinand Majerech'], 1)
|
||||
]
|
21
docsrc/index.rst
Normal file
|
@ -0,0 +1,21 @@
|
|||
================================
|
||||
Welcome to D:YAML documentation!
|
||||
================================
|
||||
|
||||
`API Documentation <api/index.html>`_
|
||||
|
||||
Tutorials:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
tutorials/getting_started
|
||||
tutorials/custom_types
|
||||
tutorials/yaml_syntax
|
||||
|
||||
Articles:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
articles/spec_differences
|
BIN
docsrc/logo128.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
docsrc/logo210.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
227
docsrc/tutorials/custom_types.rst
Normal file
|
@ -0,0 +1,227 @@
|
|||
======================
|
||||
Custom YAML data types
|
||||
======================
|
||||
|
||||
Often you will want to serialize complex data types such as classes. You can use
|
||||
functions to process nodes; e.g. a mapping containing class data members indexed
|
||||
by name. Alternatively, YAML supports custom data types using 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, so you don't need to specify tag for each float, integer, etc.
|
||||
It is also possible to implicitly resolve custom tags, as we will show later.
|
||||
|
||||
|
||||
-----------
|
||||
Constructor
|
||||
-----------
|
||||
|
||||
D:YAML uses the *Constructor* class to process each node to hold data type
|
||||
corresponding to its tag. *Constructor* stores a function for each supported
|
||||
tag to process it. These functions can be supplied by the user using the
|
||||
*addConstructor()* method. *Constructor* is then passed to *Loader*, which will
|
||||
parse YAML input.
|
||||
|
||||
We will implement support for an RGB color type. It is implemented as the
|
||||
following struct:
|
||||
|
||||
.. code-block:: d
|
||||
|
||||
struct Color
|
||||
{
|
||||
ubyte red;
|
||||
ubyte green;
|
||||
ubyte blue;
|
||||
}
|
||||
|
||||
First, we need a function to construct our data type. It must take two *Mark*
|
||||
structs, which store position of the node in the file, and 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 functions to construct a color from a scalar, using HTML-like format,
|
||||
RRGGBB, or from a mapping, where we use the following format:
|
||||
{r:RRR, g:GGG, b:BBB} . Code of these functions:
|
||||
|
||||
.. code-block:: d
|
||||
|
||||
Color constructColorScalar(Mark start, Mark end, string value)
|
||||
{
|
||||
if(value.length != 6)
|
||||
{
|
||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
||||
}
|
||||
//We don't need to check for uppercase chars this way.
|
||||
value = value.toLower();
|
||||
|
||||
//Get value of a hex digit.
|
||||
uint hex(char c)
|
||||
{
|
||||
if(!std.ascii.isHexDigit(c))
|
||||
{
|
||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
||||
}
|
||||
|
||||
if(std.ascii.isDigit(c))
|
||||
{
|
||||
return c - '0';
|
||||
}
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
|
||||
Color result;
|
||||
result.red = cast(ubyte)(16 * hex(value[0]) + hex(value[1]));
|
||||
result.green = cast(ubyte)(16 * hex(value[2]) + hex(value[3]));
|
||||
result.blue = cast(ubyte)(16 * hex(value[4]) + hex(value[5]));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Color constructColorMapping(Mark start, Mark end, Node.Pair[] pairs)
|
||||
{
|
||||
int r, g, b;
|
||||
r = g = b = -1;
|
||||
bool error = pairs.length != 3;
|
||||
|
||||
foreach(ref pair; pairs)
|
||||
{
|
||||
//Key might not be a string, and value might not be an int,
|
||||
//so we need to check for that
|
||||
try
|
||||
{
|
||||
switch(pair.key.get!string)
|
||||
{
|
||||
case "r": r = pair.value.get!int; break;
|
||||
case "g": g = pair.value.get!int; break;
|
||||
case "b": b = pair.value.get!int; break;
|
||||
default: error = true;
|
||||
}
|
||||
}
|
||||
catch(NodeException e)
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
|
||||
{
|
||||
throw new ConstructorException("Invalid color", start, end);
|
||||
}
|
||||
|
||||
return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b);
|
||||
}
|
||||
|
||||
Next, we need some YAML code using our new tag. Create a file called input.yaml
|
||||
with the following contents:
|
||||
|
||||
.. code-block:: 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:
|
||||
|
||||
.. code-block:: d
|
||||
|
||||
void main()
|
||||
{
|
||||
auto red = Color(255, 0, 0);
|
||||
auto orange = Color(255, 255, 0);
|
||||
|
||||
try
|
||||
{
|
||||
auto constructor = new Constructor;
|
||||
//both functions handle the same tag, but one handles scalar, one mapping.
|
||||
constructor.addConstructor("!color", &constructColorScalar);
|
||||
constructor.addConstructor("!color-mapping", &constructColorMapping);
|
||||
|
||||
auto loader = new Loader("input.yaml", constructor, new Resolver);
|
||||
|
||||
auto root = loader.loadSingleDocument();
|
||||
|
||||
if(root["scalar-red"].get!Color == red &&
|
||||
root["mapping-red"].get!Color == red &&
|
||||
root["scalar-orange"].get!Color == orange &&
|
||||
root["mapping-orange"].get!Color == orange)
|
||||
{
|
||||
writeln("SUCCESS");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch(YAMLException e)
|
||||
{
|
||||
writeln(e.msg);
|
||||
}
|
||||
|
||||
writeln("FAILURE");
|
||||
}
|
||||
|
||||
First, we create a *Constructor* and pass functions to handle the ``!color``
|
||||
and ``!color-mapping`` tag. We construct a *Loader* using the *Constructor*.
|
||||
We also need a *Resolver*, but for now we just default-construct it. We then
|
||||
load the YAML document, and finally, read the colors using *get()* method to
|
||||
test if they were loaded as expected.
|
||||
|
||||
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 value can be tedious. D:YAML can implicitly
|
||||
resolve tag of a scalar using a regular expression. This is how default types,
|
||||
e.g. int, are resolved. We will use the *Resolver* 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 value must match to resolve to this tag, and a string of possible
|
||||
starting characters of the value. Then we pass the *Resolver* to the constructor
|
||||
of *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``.
|
||||
|
||||
.. code-block:: d
|
||||
|
||||
//code from the previous example...
|
||||
|
||||
auto resolver = new Resolver;
|
||||
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}",
|
||||
"0123456789abcdefABCDEF"));
|
||||
|
||||
auto loader = new Loader("input.yaml", constructor, resolver);
|
||||
|
||||
//code from the previous example...
|
||||
|
||||
Now, change contents of input.dyaml to this:
|
||||
|
||||
.. code-block:: 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.
|
168
docsrc/tutorials/getting_started.rst
Normal file
|
@ -0,0 +1,168 @@
|
|||
===============
|
||||
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://d-p-l.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 the
|
||||
information present might already be known to you. Only basic usage is covered.
|
||||
More advanced usage is described in other tutorials.
|
||||
|
||||
|
||||
----------
|
||||
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://www.digitalmars.com/d/download.html>`_.
|
||||
Download the version of DMD for your operating system and install it.
|
||||
|
||||
.. note::
|
||||
Other D compilers exist, such as
|
||||
`GDC <http://bitbucket.org/goshawk/gdc/wiki/Home>`_ and
|
||||
`LDC <http://www.dsource.org/projects/ldc/>`_.
|
||||
Setting up with either one of them should be similar to DMD,
|
||||
however, at the moment they are not as up to date as DMD.
|
||||
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Download and compile D:YAML
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The newest version of D:YAML can be found `here <TODO>`_. Download a source
|
||||
archive, extract it, and move to the extracted directory.
|
||||
|
||||
D:YAML uses a modified version of the `CDC <http://dsource.org/projects/cdc/>`_
|
||||
script for compilation. To compile D:YAML, you first need to build CDC.
|
||||
Do this by typing the following command into the console::
|
||||
|
||||
dmd cdc.d
|
||||
|
||||
Now you can use CDC to compile D:YAML.
|
||||
To do this on Unix/Linux, use the following command::
|
||||
|
||||
./cdc
|
||||
|
||||
On Windows::
|
||||
|
||||
cdc.exe
|
||||
|
||||
This will compile the library to a file called ``libdyaml.a`` on Unix/Linux or
|
||||
``libdyaml.lib`` on Windows.
|
||||
|
||||
|
||||
-------------------------
|
||||
Your first D:YAML project
|
||||
-------------------------
|
||||
|
||||
Create a directory for your project and in that directory, create a file called
|
||||
``input.yaml`` with the following contents:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Hello World :
|
||||
- Hello
|
||||
- World
|
||||
Answer: 42
|
||||
|
||||
This will serve as input for our example.
|
||||
|
||||
Now we need to parse it. Create a file called "main.d". Paste following code
|
||||
into the file:
|
||||
|
||||
.. code-block:: d
|
||||
|
||||
import std.stdio;
|
||||
import yaml;
|
||||
|
||||
void main()
|
||||
{
|
||||
yaml.Node root = yaml.load("input.yaml");
|
||||
foreach(string word; root["Hello World"])
|
||||
{
|
||||
writeln(word);
|
||||
}
|
||||
writeln("The answer is ", root["Answer"].get!int);
|
||||
}
|
||||
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Explanation of the code
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
First, we import the *yaml* module. This is the only module you need to import
|
||||
to use D:YAML - it automatically imports all needed modules.
|
||||
|
||||
Next we load the file using the *yaml.load()* function - this loads the file as
|
||||
**one** YAML document and throws *YAMLException*, D:YAML exception type, if the
|
||||
file could not be parsed or does not contain exactly one document. Note that we
|
||||
don't do any error checking here in order to keep the example as simple as
|
||||
possible.
|
||||
|
||||
*yaml.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 first, as it is a sequence, and use the
|
||||
*yaml.Node.get()* method on the second to get its value as an integer.
|
||||
|
||||
You can iterate over a mapping or sequence as if it was an associative or normal
|
||||
array. If you try to iterate over a scalar, it will throw a *YAMLException*.
|
||||
|
||||
You can iterate over subnodes using yaml.Node as the iterated type, or specify
|
||||
the type subnodes are expected to have. D:YAML will automatically convert
|
||||
iterated subnodes 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 *yaml.Node.get()* method is used to get value of a scalar node as specified
|
||||
type. D:YAML will try to return the scalar as specified type, converting if
|
||||
needed, throwing *YAMLException* if not possible.
|
||||
|
||||
|
||||
^^^^^^^^^
|
||||
Compiling
|
||||
^^^^^^^^^
|
||||
|
||||
To compile your project, you must give DMD the directories containing import
|
||||
modules and the library. You also need to tell it to link with D:YAML. The import
|
||||
directory should be the D:YAML package directory. You can specify it using the
|
||||
``-I`` option of DMD. The library directory should point to where you put the
|
||||
compiled D:YAML library. On Unix/Linux you can specify it using the ``-L-L``
|
||||
option, and link with D:YAML using the ``-L-l`` option. On Windows, the import
|
||||
directory is used as the library directory. To link with the library on Windows,
|
||||
just add the path to it relative to the current directory.
|
||||
|
||||
For example, if you extracted D:YAML to ``/home/xxx/dyaml`` and compiled it in
|
||||
that directory, your project is in ``/home/xxx/dyaml-project``, and you are
|
||||
currently in that directory, you can compile the project with the following
|
||||
command on Unix/Linux::
|
||||
|
||||
dmd -I../dyaml -L-L../dyaml -L-ldyaml main.d
|
||||
|
||||
And the following on Windows::
|
||||
|
||||
dmd -I../dyaml ../dyaml/libdyaml.lib main.d
|
||||
|
||||
This will produce an executable called ``main`` or ``main.exe`` in your
|
||||
directory. When you run it, it should produce the following output::
|
||||
|
||||
Hello
|
||||
World
|
||||
The answer is 42
|
||||
|
||||
|
||||
^^^^^^^^^^
|
||||
Conclusion
|
||||
^^^^^^^^^^
|
||||
|
||||
You should now have a basic idea about how to use D:YAML. To learn more, look at
|
||||
the `API documentation <../api/index.html>`_ and other tutorials. You can find code for this
|
||||
example in the ``example/getting_started`` directory in the package.
|
273
docsrc/tutorials/yaml_syntax.rst
Normal file
|
@ -0,0 +1,273 @@
|
|||
===========
|
||||
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 to be as human readable as
|
||||
possible. 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, YAML 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 either depends 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 ``...`` . If there is only one document, ``---`` can be
|
||||
left out.
|
||||
|
||||
Single document with no explicit start or end:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
|
||||
Same document with explicit start and end:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
...
|
||||
|
||||
A stream containing multiple documents:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
---
|
||||
- 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.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Block context
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Flow context
|
||||
[Red, Green, Blue]
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Nested
|
||||
-
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
-
|
||||
- Linux
|
||||
- BSD
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Nested flow
|
||||
[[Red, Green, Blue], [Linux, BSD]]
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#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:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Block context
|
||||
CPU: Athlon
|
||||
GPU: Radeon
|
||||
OS: Linux
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Flow context
|
||||
{CPU: Athlon, GPU: Radeon, OS: Linux}
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Nested
|
||||
PC:
|
||||
CPU: Athlon
|
||||
GPU: Radeon
|
||||
OS: Debian
|
||||
Phone:
|
||||
CPU: Cortex
|
||||
GPU: PowerVR
|
||||
OS: Android
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Nested flow
|
||||
{PC: {CPU: Athlon, GPU: Radeon, OS: Debian},
|
||||
Phone: {CPU: Cortex, GPU: PowerVR, OS: Android}}
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#Nested in a sequence
|
||||
- CPU: Athlon
|
||||
GPU: Radeon
|
||||
OS: Debian
|
||||
- CPU: Cortex
|
||||
GPU: PowerVR
|
||||
OS: Android
|
||||
|
||||
Complex keys start with question mark+space "? ".
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
#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:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
scalar: Plain scalar
|
||||
|
||||
Single quoted scalars start and end with single quotes. A single quote is
|
||||
represented by a pair of single quotes ''.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
scalar: 'Single quoted scalar ending with some spaces '
|
||||
|
||||
Double quoted scalars support C-style escape sequences.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
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.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
scalar: |
|
||||
Newlines are preserved
|
||||
First line
|
||||
Second line
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
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).
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
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:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
answer: !!int "42"
|
||||
name: !!str "Arthur Dent"
|
||||
|
||||
Implicit tags:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
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 yaml.YAMLNull
|
||||
!!bool bool
|
||||
!!int long
|
||||
!!float real
|
||||
!!binary ubyte[]
|
||||
!!timestamp datetime.SysTime
|
||||
!!map, !!omap, !!pairs Node.Pair[]
|
||||
!!seq, !!set Node[]
|
||||
!!str string
|
||||
====================== ================
|
324
dyaml/composer.d
Normal file
|
@ -0,0 +1,324 @@
|
|||
|
||||
// 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 std.conv;
|
||||
import std.exception;
|
||||
import std.typecons;
|
||||
|
||||
import dyaml.constructor;
|
||||
import dyaml.event;
|
||||
import dyaml.node;
|
||||
import dyaml.parser;
|
||||
import dyaml.resolver;
|
||||
import dyaml.exception;
|
||||
|
||||
|
||||
package:
|
||||
/**
|
||||
* Marked exception thrown at composer errors.
|
||||
*
|
||||
* See_Also: MarkedYAMLException
|
||||
*/
|
||||
class ComposerException : MarkedYAMLException
|
||||
{
|
||||
this(string context, Mark contextMark, string problem, Mark problemMark)
|
||||
{
|
||||
super(context, contextMark, problem, problemMark);
|
||||
}
|
||||
|
||||
this(string problem, Mark problemMark){super(problem, problemMark);}
|
||||
}
|
||||
|
||||
///Composes YAML documents from events provided by a Parser.
|
||||
final class Composer
|
||||
{
|
||||
private:
|
||||
///Parser providing YAML events.
|
||||
Parser parser_;
|
||||
///Resolver resolving tags (data types).
|
||||
Resolver resolver_;
|
||||
///Constructor constructing YAML values.
|
||||
Constructor constructor_;
|
||||
///Nodes associated with anchors. Used by YAML aliases.
|
||||
Node[string] anchors_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a composer.
|
||||
*
|
||||
* Params: parser = Parser to provide YAML events.
|
||||
* resolver = Resolver to resolve tags (data types).
|
||||
* constructor = Constructor to construct nodes.
|
||||
*/
|
||||
this(Parser parser, Resolver resolver, Constructor constructor)
|
||||
{
|
||||
parser_ = parser;
|
||||
resolver_ = resolver;
|
||||
constructor_ = constructor;
|
||||
}
|
||||
|
||||
///Destroy the composer.
|
||||
~this()
|
||||
{
|
||||
parser_ = null;
|
||||
resolver_ = null;
|
||||
constructor_ = null;
|
||||
clear(anchors_);
|
||||
anchors_ = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if there are any nodes left.
|
||||
*
|
||||
* Must be called before loading as it handles the stream start event.
|
||||
*/
|
||||
bool checkNode()
|
||||
{
|
||||
//Drop the STREAM-START event.
|
||||
if(parser_.checkEvent(EventID.StreamStart))
|
||||
{
|
||||
parser_.getEvent();
|
||||
}
|
||||
|
||||
//True if there are more documents available.
|
||||
return !parser_.checkEvent(EventID.StreamEnd);
|
||||
}
|
||||
|
||||
///Get a YAML document as a node (the root of the document).
|
||||
Node getNode()
|
||||
{
|
||||
//Get the root node of the next document.
|
||||
assert(!parser_.checkEvent(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();
|
||||
}
|
||||
|
||||
///Get single YAML document, throwing if there is more than one document.
|
||||
Node getSingleNode()
|
||||
{
|
||||
assert(!parser_.checkEvent(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.");
|
||||
|
||||
Node document = composeDocument();
|
||||
|
||||
//Ensure that the stream contains no more documents.
|
||||
enforce(parser_.checkEvent(EventID.StreamEnd),
|
||||
new ComposerException("Expected single document in the stream, "
|
||||
"but found another document: ",
|
||||
parser_.getEvent().startMark));
|
||||
|
||||
//Drop the STREAM-END event.
|
||||
parser_.getEvent();
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
private:
|
||||
///Compose a YAML document and return its root node.
|
||||
Node composeDocument()
|
||||
{
|
||||
//Drop the DOCUMENT-START event.
|
||||
parser_.getEvent();
|
||||
|
||||
//Compose the root node.
|
||||
Node node = composeNode();
|
||||
|
||||
//Drop the DOCUMENT-END event.
|
||||
parser_.getEvent();
|
||||
|
||||
//Clear anchors.
|
||||
Node[string] empty;
|
||||
anchors_ = empty;
|
||||
return node;
|
||||
}
|
||||
|
||||
///Compose a node.
|
||||
Node composeNode()
|
||||
{
|
||||
if(parser_.checkEvent(EventID.Alias))
|
||||
{
|
||||
Event event = parser_.getEvent();
|
||||
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];
|
||||
}
|
||||
|
||||
Event event = parser_.peekEvent();
|
||||
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();}
|
||||
|
||||
if(parser_.checkEvent(EventID.Scalar))
|
||||
{
|
||||
result = composeScalarNode();
|
||||
}
|
||||
else if(parser_.checkEvent(EventID.SequenceStart))
|
||||
{
|
||||
result = composeSequenceNode();
|
||||
}
|
||||
else if(parser_.checkEvent(EventID.MappingStart))
|
||||
{
|
||||
result = composeMappingNode();
|
||||
}
|
||||
else{assert(false, "This code should never be reached");}
|
||||
|
||||
if(anchor !is null){anchors_[anchor] = result;}
|
||||
return result;
|
||||
}
|
||||
|
||||
///Compose a scalar node.
|
||||
Node composeScalarNode()
|
||||
{
|
||||
Event event = parser_.getEvent();
|
||||
const tag = resolver_.resolve(NodeID.Scalar, event.tag, event.value,
|
||||
event.implicit);
|
||||
|
||||
Node node = constructor_.node(event.startMark, event.endMark, tag,
|
||||
event.value);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
///Compose a sequence node.
|
||||
Node composeSequenceNode()
|
||||
{
|
||||
Event startEvent = parser_.getEvent();
|
||||
const tag = resolver_.resolve(NodeID.Sequence, startEvent.tag, null,
|
||||
startEvent.implicit);
|
||||
|
||||
Node[] children;
|
||||
while(!parser_.checkEvent(EventID.SequenceEnd))
|
||||
{
|
||||
children ~= composeNode();
|
||||
}
|
||||
|
||||
Node node = constructor_.node(startEvent.startMark, parser_.getEvent().endMark,
|
||||
tag, children);
|
||||
|
||||
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.
|
||||
*
|
||||
* Returns: Flattened mapping as pairs.
|
||||
*/
|
||||
Node.Pair[] flatten(ref Node root, in Mark startMark, in Mark endMark)
|
||||
{
|
||||
Node.Pair[] result;
|
||||
|
||||
if(root.isMapping)
|
||||
{
|
||||
Node[] toMerge;
|
||||
foreach(ref Node key, ref Node value; root)
|
||||
{
|
||||
if(key.isType!YAMLMerge){toMerge ~= value;}
|
||||
else{merge(result, Node.Pair(key, value));}
|
||||
}
|
||||
foreach(node; toMerge)
|
||||
{
|
||||
merge(result, flatten(node, startMark, endMark));
|
||||
}
|
||||
}
|
||||
else if(root.isSequence)
|
||||
{
|
||||
//Must be a sequence of mappings.
|
||||
foreach(ref Node node; root)
|
||||
{
|
||||
//this is Composer, but the code is related to constructor
|
||||
enforce(node.isType!(Node.Pair[]),
|
||||
new ConstructorException("While constructing a mapping, " ~
|
||||
"expected a mapping for merging, but found"
|
||||
~ node.value_.type.toString() ~
|
||||
"NOTE: line/column shows topmost parent "
|
||||
"to which the content is being merged",
|
||||
startMark, endMark));
|
||||
merge(result, flatten(node, startMark, endMark));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//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: "
|
||||
~ root.value_.type.toString() ~
|
||||
"NOTE: line/column shows topmost parent "
|
||||
"to which the content is being merged",
|
||||
startMark, endMark);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
///Compose a mapping node.
|
||||
Node composeMappingNode()
|
||||
{
|
||||
Event startEvent = parser_.getEvent();
|
||||
string tag = resolver_.resolve(NodeID.Mapping, startEvent.tag, null,
|
||||
startEvent.implicit);
|
||||
|
||||
Node.Pair[] children;
|
||||
Tuple!(Node, Mark)[] toMerge;
|
||||
while(!parser_.checkEvent(EventID.MappingEnd))
|
||||
{
|
||||
auto pair = Node.Pair(composeNode(), composeNode());
|
||||
|
||||
//Need to flatten and merge the node referred by YAMLMerge.
|
||||
if(pair.key.isType!YAMLMerge)
|
||||
{
|
||||
toMerge ~= tuple(pair.value, cast(Mark)parser_.peekEvent().endMark);
|
||||
}
|
||||
//Not YAMLMerge, just add the pair.
|
||||
else
|
||||
{
|
||||
merge(children, pair);
|
||||
}
|
||||
}
|
||||
foreach(node; toMerge)
|
||||
{
|
||||
merge(children, flatten(node[0], startEvent.startMark, node[1]));
|
||||
}
|
||||
|
||||
Node node = constructor_.node(startEvent.startMark, parser_.getEvent().endMark,
|
||||
tag, children);
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
683
dyaml/constructor.d
Normal file
|
@ -0,0 +1,683 @@
|
|||
|
||||
// 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 processes YAML mappings, sequences and scalars into
|
||||
* nodes. This can be used to implement custom data types. A tutorial can be
|
||||
* found $(LINK2 ../tutorials/custom_types.html, here).
|
||||
*/
|
||||
module dyaml.constructor;
|
||||
|
||||
|
||||
import std.array;
|
||||
import std.algorithm;
|
||||
import std.base64;
|
||||
import std.conv;
|
||||
import std.datetime;
|
||||
import std.exception;
|
||||
import std.stdio;
|
||||
import std.regex;
|
||||
import std.string;
|
||||
import std.utf;
|
||||
|
||||
import dyaml.node;
|
||||
import dyaml.exception;
|
||||
import dyaml.token;
|
||||
|
||||
|
||||
/**
|
||||
* Exception thrown at constructor errors.
|
||||
*
|
||||
* Can be thrown by custom constructor functions.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
super(msg ~ "\nstart:" ~ start.toString() ~ "\nend:" ~ end.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
final class Constructor
|
||||
{
|
||||
private:
|
||||
///Constructor functions from scalars.
|
||||
Node.Value delegate(Mark, Mark, string) [string] fromScalar_;
|
||||
///Constructor functions from sequences.
|
||||
Node.Value delegate(Mark, Mark, Node[]) [string] fromSequence_;
|
||||
///Constructor functions from mappings.
|
||||
Node.Value delegate (Mark, Mark, Node.Pair[])[string] fromMapping_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a Constructor.
|
||||
*
|
||||
* If you don't want to support default YAML tags/data types, you can use
|
||||
* defaultConstructors to disable constructor functions for these.
|
||||
*
|
||||
* Params: defaultConstructors = Use constructors for default YAML tags?
|
||||
*/
|
||||
this(in bool defaultConstructors = true)
|
||||
{
|
||||
if(defaultConstructors)
|
||||
{
|
||||
addConstructor("tag:yaml.org,2002:null", &constructNull);
|
||||
addConstructor("tag:yaml.org,2002:bool", &constructBool);
|
||||
addConstructor("tag:yaml.org,2002:int", &constructLong);
|
||||
addConstructor("tag:yaml.org,2002:float", &constructReal);
|
||||
addConstructor("tag:yaml.org,2002:binary", &constructBinary);
|
||||
addConstructor("tag:yaml.org,2002:timestamp", &constructTimestamp);
|
||||
addConstructor("tag:yaml.org,2002:str", &constructString);
|
||||
|
||||
///In a mapping, the default value is kept as an entry with the '=' key.
|
||||
addConstructor("tag:yaml.org,2002:value", &constructString);
|
||||
|
||||
addConstructor("tag:yaml.org,2002:omap", &constructOrderedMap);
|
||||
addConstructor("tag:yaml.org,2002:pairs", &constructPairs);
|
||||
addConstructor("tag:yaml.org,2002:set", &constructSet);
|
||||
addConstructor("tag:yaml.org,2002:seq", &constructSequence);
|
||||
addConstructor("tag:yaml.org,2002:map", &constructMap);
|
||||
addConstructor("tag:yaml.org,2002:merge", &constructMerge);
|
||||
}
|
||||
}
|
||||
|
||||
///Destroy the constructor.
|
||||
~this()
|
||||
{
|
||||
clear(fromScalar_);
|
||||
fromScalar_ = null;
|
||||
clear(fromSequence_);
|
||||
fromSequence_ = null;
|
||||
clear(fromMapping_);
|
||||
fromMapping_ = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a constructor function.
|
||||
*
|
||||
* The function passed must two Marks (determining start and end positions of
|
||||
* the node in file) and either a string (if constructing from scalar),
|
||||
* an array of Nodes (from sequence) or an array of Node.Pair (from mapping).
|
||||
* The value returned by this function will be stored in the resulring node.
|
||||
*
|
||||
* Params: tag = Tag for the function to handle.
|
||||
* ctor = Constructor function.
|
||||
*/
|
||||
void addConstructor(T, U)(in string tag, T function(Mark, Mark, U) ctor)
|
||||
if(is(U == string) || is(U == Node[]) || is(U == Node.Pair[]))
|
||||
{
|
||||
Node.Value delegate(Mark, Mark, U) deleg;
|
||||
|
||||
//Type that natively fits into Node.Value.
|
||||
static if(Node.Value.allowed!T)
|
||||
{
|
||||
deleg = (Mark s, Mark e, U p){return Node.Value(ctor(s,e,p));};
|
||||
}
|
||||
//User defined type.
|
||||
else
|
||||
{
|
||||
deleg = (Mark s, Mark e, U p){return Node.userValue(ctor(s,e,p));};
|
||||
}
|
||||
|
||||
assert((tag in fromScalar_) is null &&
|
||||
(tag in fromSequence_) is null &&
|
||||
(tag in fromMapping_) is null,
|
||||
"Constructor function for tag " ~ tag ~ " is already "
|
||||
"specified. Can't specify another one.");
|
||||
|
||||
|
||||
static if(is(U == string))
|
||||
{
|
||||
fromScalar_[tag] = deleg;
|
||||
}
|
||||
else static if(is(U == Node[]))
|
||||
{
|
||||
fromSequence_[tag] = deleg;
|
||||
}
|
||||
else static if(is(U == Node.Pair[]))
|
||||
{
|
||||
fromMapping_[tag] = deleg;
|
||||
}
|
||||
}
|
||||
|
||||
package:
|
||||
/*
|
||||
* Construct a node from scalar.
|
||||
*
|
||||
* Params: start = Start position of the node.
|
||||
* end = End position of the node.
|
||||
* value = String value of the node.
|
||||
*
|
||||
* Returns: Constructed node.
|
||||
*/
|
||||
Node node(in Mark start, in Mark end, in string tag, string value) const
|
||||
{
|
||||
enforce((tag in fromScalar_) !is null,
|
||||
new ConstructorException("Could not determine a constructor from "
|
||||
"scalar for tag " ~ tag, start, end));
|
||||
return Node(fromScalar_[tag](start, end, value), start, end);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a node from sequence.
|
||||
*
|
||||
* Params: start = Start position of the node.
|
||||
* end = End position of the node.
|
||||
* value = Sequence to construct node from.
|
||||
*
|
||||
* Returns: Constructed node.
|
||||
*/
|
||||
Node node(in Mark start, in Mark end, in string tag, Node[] value) const
|
||||
{
|
||||
enforce((tag in fromSequence_) !is null,
|
||||
new ConstructorException("Could not determine a constructor from "
|
||||
"sequence for tag " ~ tag, start, end));
|
||||
return Node(fromSequence_[tag](start, end, value), start, end);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a node from mapping.
|
||||
*
|
||||
* Params: start = Start position of the node.
|
||||
* end = End position of the node.
|
||||
* value = Mapping to construct node from.
|
||||
*
|
||||
* Returns: Constructed node.
|
||||
*/
|
||||
Node node(in Mark start, in Mark end, in string tag, Node.Pair[] value) const
|
||||
{
|
||||
enforce((tag in fromMapping_) !is null,
|
||||
new ConstructorException("Could not determine a constructor from "
|
||||
"mapping for tag " ~ tag, start, end));
|
||||
return Node(fromMapping_[tag](start, end, value), start, end);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///Construct a null node.
|
||||
YAMLNull constructNull(Mark start, Mark end, string value)
|
||||
{
|
||||
return YAMLNull();
|
||||
}
|
||||
|
||||
///Construct a merge node - a node that merges another node into a mapping.
|
||||
YAMLMerge constructMerge(Mark start, Mark end, string value)
|
||||
{
|
||||
return YAMLMerge();
|
||||
}
|
||||
|
||||
///Construct a boolean node.
|
||||
bool constructBool(Mark start, Mark end, string value)
|
||||
{
|
||||
value = value.toLower();
|
||||
if(["yes", "true", "on"].canFind(value)) {return true;}
|
||||
if(["no", "false", "off"].canFind(value)){return false;}
|
||||
throw new ConstructorException("Unable to parse boolean value: " ~ value, start, end);
|
||||
}
|
||||
|
||||
///Construct an integer (long) node.
|
||||
long constructLong(Mark start, Mark end, string value)
|
||||
{
|
||||
value = value.replace("_", "");
|
||||
const char c = value[0];
|
||||
const long sign = c != '-' ? 1 : -1;
|
||||
if(c == '-' || c == '+')
|
||||
{
|
||||
value = value[1 .. $];
|
||||
}
|
||||
|
||||
enforce(value != "", new ConstructorException("Unable to parse float value: " ~ value,
|
||||
start, end));
|
||||
|
||||
long result;
|
||||
try
|
||||
{
|
||||
//Zero.
|
||||
if(value == "0") {result = cast(long)0;}
|
||||
//Binary.
|
||||
else if(value.startsWith("0b")){result = sign * parse!int(value[2 .. $], 2);}
|
||||
//Hexadecimal.
|
||||
else if(value.startsWith("0x")){result = sign * parse!int(value[2 .. $], 16);}
|
||||
//Octal.
|
||||
else if(value[0] == '0') {result = sign * parse!int(value, 8);}
|
||||
//Sexagesimal.
|
||||
else if(value.canFind(":"))
|
||||
{
|
||||
long val = 0;
|
||||
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 ConstructorException("Unable to parse integer value: " ~ value, start, end);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
unittest
|
||||
{
|
||||
long getLong(string str)
|
||||
{
|
||||
return constructLong(Mark(), Mark(), str);
|
||||
}
|
||||
|
||||
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 == getLong(canonical));
|
||||
assert(685230 == getLong(decimal));
|
||||
assert(685230 == getLong(octal));
|
||||
assert(685230 == getLong(hexadecimal));
|
||||
assert(685230 == getLong(binary));
|
||||
assert(685230 == getLong(sexagesimal));
|
||||
}
|
||||
|
||||
///Construct a floating point (real) node.
|
||||
real constructReal(Mark start, Mark end, string value)
|
||||
{
|
||||
value = value.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 ConstructorException("Unable to parse float value: " ~ value, start, end));
|
||||
|
||||
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 ConstructorException("Unable to parse float value: " ~ value, start, end);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
unittest
|
||||
{
|
||||
bool eq(real a, real b, real epsilon = 0.2)
|
||||
{
|
||||
return a >= (b - epsilon) && a <= (b + epsilon);
|
||||
}
|
||||
|
||||
real getReal(string str)
|
||||
{
|
||||
return constructReal(Mark(), Mark(), str);
|
||||
}
|
||||
|
||||
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, getReal(canonical)));
|
||||
assert(eq(685230.15, getReal(exponential)));
|
||||
assert(eq(685230.15, getReal(fixed)));
|
||||
assert(eq(685230.15, getReal(sexagesimal)));
|
||||
assert(eq(-real.infinity, getReal(negativeInf)));
|
||||
assert(to!string(getReal(NaN)) == "nan");
|
||||
}
|
||||
|
||||
///Construct a binary (base64) node.
|
||||
ubyte[] constructBinary(Mark start, Mark end, string value)
|
||||
{
|
||||
//For an unknown reason, this must be nested to work (compiler bug?).
|
||||
try
|
||||
{
|
||||
try{return Base64.decode(value.removechars("\n"));}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw new ConstructorException("Unable to decode base64 value: " ~ e.msg, start,
|
||||
end);
|
||||
}
|
||||
}
|
||||
catch(UtfException e)
|
||||
{
|
||||
throw new ConstructorException("Unable to decode base64 value: " ~ e.msg, start, end);
|
||||
}
|
||||
}
|
||||
unittest
|
||||
{
|
||||
ubyte[] test = cast(ubyte[])"The Answer: 42";
|
||||
char[] buffer;
|
||||
buffer.length = 256;
|
||||
string input = cast(string)Base64.encode(test, buffer);
|
||||
auto value = constructBinary(Mark(), Mark(), input);
|
||||
assert(value == test);
|
||||
}
|
||||
|
||||
///Construct a timestamp (SysTime) node.
|
||||
SysTime constructTimestamp(Mark start, Mark end, string value)
|
||||
{
|
||||
immutable YMDRegexp = regex("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)");
|
||||
immutable HMSRegexp = regex("^[Tt \t]+([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(\\.[0-9]*)?");
|
||||
immutable 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 ConstructorException("Unable to parse timestamp value: "
|
||||
~ value, start, end));
|
||||
|
||||
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]) * 10000000);
|
||||
|
||||
//If available, get timezone.
|
||||
value = matches.front.post;
|
||||
matches = match(value, TZRegexp);
|
||||
if(matches.empty || matches.front.captures[0] == "Z")
|
||||
{
|
||||
return SysTime(DateTime(year, month, day, hour, minute, second),
|
||||
FracSec.from!"hnsecs"(hectonanosecond), UTC());
|
||||
}
|
||||
|
||||
captures = matches.front.captures;
|
||||
int sign = 1;
|
||||
int tzHours = 0;
|
||||
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 = sign * (60 * tzHours + tzMinutes);
|
||||
|
||||
return SysTime(DateTime(year, month, day, hour, minute, second),
|
||||
FracSec.from!"hnsecs"(hectonanosecond),
|
||||
new SimpleTimeZone(tzOffset));
|
||||
}
|
||||
catch(ConvException e)
|
||||
{
|
||||
throw new ConstructorException("Unable to parse timestamp value: " ~ value ~
|
||||
" Reason: " ~ e.msg, start, end);
|
||||
}
|
||||
catch(DateTimeException e)
|
||||
{
|
||||
throw new ConstructorException("Invalid timestamp value: " ~ value ~
|
||||
" Reason: " ~ e.msg, start, end);
|
||||
}
|
||||
|
||||
assert(false, "This code should never be reached");
|
||||
}
|
||||
unittest
|
||||
{
|
||||
writeln("D:YAML construction timestamp unittest");
|
||||
|
||||
string timestamp(string value)
|
||||
{
|
||||
return constructTimestamp(Mark(), Mark(), 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(Mark start, Mark end, string value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
///Convert a sequence of single-element mappings into a sequence of pairs.
|
||||
Node.Pair[] getPairs(string type, Mark start, Mark end, Node[] nodes)
|
||||
{
|
||||
Node.Pair[] pairs;
|
||||
|
||||
foreach(ref node; nodes)
|
||||
{
|
||||
enforce(node.isMapping && node.length == 1,
|
||||
new ConstructorException("While constructing " ~ type ~
|
||||
", expected a mapping with single element,", start,
|
||||
end));
|
||||
|
||||
pairs ~= node.get!(Node.Pair[]);
|
||||
}
|
||||
|
||||
return pairs;
|
||||
}
|
||||
|
||||
///Construct an ordered map (ordered sequence of key:value pairs without duplicates) node.
|
||||
Node.Pair[] constructOrderedMap(Mark start, Mark end, Node[] nodes)
|
||||
{
|
||||
auto pairs = getPairs("ordered map", start, end, nodes);
|
||||
|
||||
//In future, the map here should be replaced with something with deterministic
|
||||
//memory allocation if possible.
|
||||
//Detect duplicates.
|
||||
Node[Node] map;
|
||||
foreach(ref pair; pairs)
|
||||
{
|
||||
enforce((pair.key in map) is null,
|
||||
new ConstructorException("Found a duplicate entry in an ordered map",
|
||||
start, end));
|
||||
map[pair.key] = pair.value;
|
||||
}
|
||||
clear(map);
|
||||
return pairs;
|
||||
}
|
||||
unittest
|
||||
{
|
||||
writeln("D:YAML construction ordered map unittest");
|
||||
|
||||
alias Node.Pair Pair;
|
||||
|
||||
Node[] alternateTypes(uint length)
|
||||
{
|
||||
Node[] pairs;
|
||||
foreach(long i; 0 .. length)
|
||||
{
|
||||
auto pair = (i % 2) ? Pair(Node(Node.Value(to!string(i))), Node(Node.Value(i)))
|
||||
: Pair(Node(Node.Value(i)), Node(Node.Value(to!string(i))));
|
||||
pairs ~= Node(Node.Value([pair]));
|
||||
}
|
||||
return pairs;
|
||||
}
|
||||
|
||||
Node[] sameType(uint length)
|
||||
{
|
||||
Node[] pairs;
|
||||
foreach(long i; 0 .. length)
|
||||
{
|
||||
auto pair = Pair(Node(Node.Value(to!string(i))), Node(Node.Value(i)));
|
||||
pairs ~= Node(Node.Value([pair]));
|
||||
}
|
||||
return pairs;
|
||||
}
|
||||
|
||||
bool hasDuplicates(Node[] nodes)
|
||||
{
|
||||
return null !is collectException(constructOrderedMap(Mark(), Mark(), nodes));
|
||||
}
|
||||
|
||||
assert(hasDuplicates(alternateTypes(8) ~ alternateTypes(2)));
|
||||
assert(!hasDuplicates(alternateTypes(8)));
|
||||
assert(hasDuplicates(sameType(64) ~ sameType(16)));
|
||||
assert(hasDuplicates(alternateTypes(64) ~ alternateTypes(16)));
|
||||
assert(!hasDuplicates(sameType(64)));
|
||||
assert(!hasDuplicates(alternateTypes(64)));
|
||||
}
|
||||
|
||||
///Construct a pairs (ordered sequence of key: value pairs allowing duplicates) node.
|
||||
Node.Pair[] constructPairs(Mark start, Mark end, Node[] nodes)
|
||||
{
|
||||
return getPairs("pairs", start, end, nodes);
|
||||
}
|
||||
|
||||
///Construct a set node.
|
||||
Node[] constructSet(Mark start, Mark end, Node.Pair[] pairs)
|
||||
{
|
||||
//In future, the map here should be replaced with something with deterministic
|
||||
//memory allocation if possible.
|
||||
//Detect duplicates.
|
||||
ubyte[Node] map;
|
||||
Node[] nodes;
|
||||
foreach(ref pair; pairs)
|
||||
{
|
||||
enforce((pair.key in map) is null,
|
||||
new ConstructorException("Found a duplicate entry in a set", start, end));
|
||||
map[pair.key] = 0;
|
||||
nodes ~= pair.key;
|
||||
}
|
||||
|
||||
clear(map);
|
||||
return nodes;
|
||||
}
|
||||
unittest
|
||||
{
|
||||
writeln("D:YAML construction set unittest");
|
||||
|
||||
Node.Pair[] set(uint length)
|
||||
{
|
||||
Node.Pair[] pairs;
|
||||
foreach(long i; 0 .. length)
|
||||
{
|
||||
pairs ~= Node.Pair(Node(Node.Value(to!string(i))), Node());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
assert(null !is collectException
|
||||
(constructSet(Mark(), Mark(), DuplicatesShort.dup)));
|
||||
assert(null is collectException
|
||||
(constructSet(Mark(), Mark(), noDuplicatesShort.dup)));
|
||||
assert(null !is collectException
|
||||
(constructSet(Mark(), Mark(), DuplicatesLong.dup)));
|
||||
assert(null is collectException
|
||||
(constructSet(Mark(), Mark(), noDuplicatesLong.dup)));
|
||||
}
|
||||
|
||||
///Construct a sequence (array) node.
|
||||
Node[] constructSequence(Mark start, Mark end, Node[] nodes)
|
||||
{
|
||||
return nodes;
|
||||
}
|
||||
|
||||
///Construct an unordered map (unordered set of key: value _pairs without duplicates) node.
|
||||
Node.Pair[] constructMap(Mark start, Mark end, Node.Pair[] pairs)
|
||||
{
|
||||
//In future, the map here should be replaced with something with deterministic
|
||||
//memory allocation if possible.
|
||||
//Detect duplicates.
|
||||
Node[Node] map;
|
||||
foreach(ref pair; pairs)
|
||||
{
|
||||
enforce((pair.key in map) is null,
|
||||
new ConstructorException("Found a duplicate entry in a map", start, end));
|
||||
map[pair.key] = pair.value;
|
||||
}
|
||||
|
||||
clear(map);
|
||||
return pairs;
|
||||
}
|
153
dyaml/event.d
Normal file
|
@ -0,0 +1,153 @@
|
|||
|
||||
// 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 std.typecons;
|
||||
|
||||
import dyaml.reader;
|
||||
import dyaml.token;
|
||||
import dyaml.exception;
|
||||
|
||||
|
||||
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.
|
||||
*
|
||||
* 64 bytes on 64-bit.
|
||||
*/
|
||||
immutable struct Event
|
||||
{
|
||||
///Start position of the event in file/stream.
|
||||
Mark startMark;
|
||||
///End position of the event in file/stream.
|
||||
Mark endMark;
|
||||
///Anchor of the event, if any.
|
||||
string anchor;
|
||||
///Tag of the event, if any.
|
||||
string tag;
|
||||
///Value of the event, if any.
|
||||
string value;
|
||||
///Event type.
|
||||
EventID id;
|
||||
///Style of scalar event, if this is a scalar event.
|
||||
ScalarStyle style;
|
||||
///Should the tag be implicitly resolved?
|
||||
bool implicit;
|
||||
/**
|
||||
* Is this document event explicit?
|
||||
*
|
||||
* Used if this is a DocumentStart or DocumentEnd.
|
||||
*/
|
||||
alias implicit explicitDocument;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)(in Mark start, in Mark end, in string anchor = null) pure
|
||||
{
|
||||
return Event(start, end, anchor, null, null, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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?
|
||||
*/
|
||||
Event collectionStartEvent(EventID id)(in Mark start, in Mark end, in string anchor,
|
||||
in string tag, in bool implicit) pure
|
||||
{
|
||||
static assert(id == EventID.SequenceStart || id == EventID.SequenceEnd ||
|
||||
id == EventID.MappingStart || id == EventID.MappingEnd);
|
||||
return Event(start, end, anchor, tag, null, id, ScalarStyle.Invalid, implicit);
|
||||
}
|
||||
|
||||
///Aliases for simple events.
|
||||
alias event!(EventID.StreamStart) streamStartEvent;
|
||||
alias event!(EventID.StreamEnd) streamEndEvent;
|
||||
alias event!(EventID.Alias) aliasEvent;
|
||||
alias event!(EventID.SequenceEnd) sequenceEndEvent;
|
||||
alias event!(EventID.MappingEnd) mappingEndEvent;
|
||||
|
||||
///Aliases for collection start events.
|
||||
alias collectionStartEvent!(EventID.SequenceStart) sequenceStartEvent;
|
||||
alias collectionStartEvent!(EventID.MappingStart) mappingStartEvent;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
Event documentStartEvent(Mark start, Mark end, bool explicit, string YAMLVersion) pure
|
||||
{
|
||||
return Event(start, end, null, null, YAMLVersion, EventID.DocumentStart,
|
||||
ScalarStyle.Invalid, explicit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(Mark start, Mark end, bool explicit)
|
||||
{
|
||||
return Event(start, end, null, null, null, EventID.DocumentEnd,
|
||||
ScalarStyle.Invalid, explicit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(in Mark start, in Mark end, in string anchor, in string tag,
|
||||
in bool implicit, in string value,
|
||||
in ScalarStyle style = ScalarStyle.Invalid) pure
|
||||
{
|
||||
return Event(start, end, anchor, tag, value, EventID.Scalar, style, implicit);
|
||||
}
|
75
dyaml/exception.d
Normal file
|
@ -0,0 +1,75 @@
|
|||
|
||||
// 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)
|
||||
|
||||
///D:YAML exceptions and exception related code.
|
||||
module dyaml.exception;
|
||||
|
||||
|
||||
import std.algorithm;
|
||||
import std.array;
|
||||
import std.string;
|
||||
|
||||
|
||||
///Base class for all exceptions thrown by D:YAML.
|
||||
class YAMLException : Exception
|
||||
{
|
||||
public:
|
||||
///Construct a YAMLException with specified message.
|
||||
this(string msg){super(msg);}
|
||||
|
||||
package:
|
||||
//Set name of the file that was being processed when this exception was thrown.
|
||||
@property name(in string name)
|
||||
{
|
||||
msg = name ~ ":\n" ~ msg;
|
||||
}
|
||||
}
|
||||
|
||||
///Position in a YAML stream, used for error messages.
|
||||
align(1) struct Mark
|
||||
{
|
||||
private:
|
||||
///Line number.
|
||||
ushort line_;
|
||||
///Column number.
|
||||
ushort column_;
|
||||
|
||||
public:
|
||||
///Construct a Mark with specified line and column in the file.
|
||||
this(in uint line, in uint column)
|
||||
{
|
||||
line_ = cast(ushort)min(ushort.max, line);
|
||||
column_ = cast(ushort)min(ushort.max, column);
|
||||
}
|
||||
|
||||
///Get a string representation of the mark.
|
||||
string toString() const
|
||||
{
|
||||
//Line/column numbers start at zero internally, make them start at 1.
|
||||
string clamped(ushort v){return format(v + 1, v == ushort.max ? " or higher" : "");}
|
||||
return format("line ", clamped(line_), ",column ", clamped(column_));
|
||||
}
|
||||
}
|
||||
|
||||
package:
|
||||
//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, Mark contextMark, string problem, Mark problemMark)
|
||||
{
|
||||
string msg = context ~ '\n';
|
||||
if(contextMark != problemMark){msg ~= contextMark.toString() ~ '\n';}
|
||||
msg ~= problem ~ '\n' ~ problemMark.toString() ~ '\n';
|
||||
super(msg);
|
||||
}
|
||||
|
||||
//Construct a MarkedYAMLException with specified problem.
|
||||
this(string problem, Mark problemMark)
|
||||
{
|
||||
super(problem ~ '\n' ~ problemMark.toString());
|
||||
}
|
||||
}
|
330
dyaml/loader.d
Normal file
|
@ -0,0 +1,330 @@
|
|||
|
||||
// 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 and convenience functions used to load YAML documents.
|
||||
*/
|
||||
module dyaml.loader;
|
||||
|
||||
|
||||
import std.exception;
|
||||
import std.stream;
|
||||
|
||||
import dyaml.event;
|
||||
import dyaml.node;
|
||||
import dyaml.composer;
|
||||
import dyaml.constructor;
|
||||
import dyaml.resolver;
|
||||
import dyaml.parser;
|
||||
import dyaml.reader;
|
||||
import dyaml.scanner;
|
||||
import dyaml.token;
|
||||
import dyaml.exception;
|
||||
|
||||
|
||||
/**
|
||||
* Load single YAML document from a file.
|
||||
*
|
||||
* If there is no or more than one YAML document in the file, this will throw.
|
||||
* Use $(LREF loadAll) for such files.
|
||||
*
|
||||
* Params: filename = Name of the file to _load from.
|
||||
*
|
||||
* Returns: Root node of the document.
|
||||
*
|
||||
* Throws: YAMLException if there wasn't exactly one document in the file,
|
||||
* the file could not be opened or on a YAML parsing error.
|
||||
*/
|
||||
Node load(in string filename)
|
||||
{
|
||||
auto loader = Loader(filename);
|
||||
return loader.loadSingleDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load single YAML document from a stream.
|
||||
*
|
||||
* You can use this to e.g _load YAML from memory.
|
||||
*
|
||||
* If there is no or more than one YAML document in the stream, this will throw.
|
||||
* Use $(LREF loadAll) for such files.
|
||||
*
|
||||
* Params: input = Stream to read from. Must be readable.
|
||||
* name = Name of the stream, used in error messages.
|
||||
*
|
||||
* Returns: Root node of the document.
|
||||
*
|
||||
* Throws: YAMLException if there wasn't exactly one document in the stream,
|
||||
* the stream could not be read from or on a YAML parsing error.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* Loading YAML from memory:
|
||||
* --------------------
|
||||
* import std.stream;
|
||||
* import std.stdio;
|
||||
*
|
||||
* string yaml_input = "red: '#ff0000'\n"
|
||||
* "green: '#00ff00'\n"
|
||||
* "blue: '#0000ff'";
|
||||
*
|
||||
* auto colors = yaml.load(new MemoryStream(cast(char[])yaml_input));
|
||||
*
|
||||
* foreach(string color, string value; colors)
|
||||
* {
|
||||
* writeln(color, " is ", value, " in HTML/CSS");
|
||||
* }
|
||||
* --------------------
|
||||
*/
|
||||
Node load(Stream input, in string name = "<unknown>")
|
||||
{
|
||||
auto loader = Loader(input, name, new Constructor, new Resolver);
|
||||
return loader.loadSingleDocument();
|
||||
}
|
||||
unittest
|
||||
{
|
||||
import std.stream;
|
||||
import std.stdio;
|
||||
|
||||
string yaml_input = "red: '#ff0000'\n"
|
||||
"green: '#00ff00'\n"
|
||||
"blue: '#0000ff'";
|
||||
|
||||
auto colors = load(new MemoryStream(cast(char[])yaml_input));
|
||||
|
||||
foreach(string color, string value; colors)
|
||||
{
|
||||
writeln(color, " is ", value, " in HTML/CSS");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all YAML documents from a file.
|
||||
*
|
||||
* Params: filename = Name of the file to load from.
|
||||
*
|
||||
* Returns: Array of root nodes of documents in the stream.
|
||||
* If the stream is empty, empty array will be returned.
|
||||
*
|
||||
* Throws: YAMLException if the file could not be opened or on a YAML parsing error.
|
||||
*/
|
||||
Node[] loadAll(in string filename)
|
||||
{
|
||||
auto loader = Loader(filename);
|
||||
Node[] result;
|
||||
foreach(ref node; loader){result ~= node;}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load all YAML documents from a stream.
|
||||
*
|
||||
* Params: input = Stream to read from. Must be readable.
|
||||
* name = Name of the stream, used in error messages.
|
||||
*
|
||||
* Returns: Array of root nodes of documents in the file.
|
||||
* If the file is empty, empty array will be returned.
|
||||
*
|
||||
* Throws: YAMLException if the stream could not be read from or on a YAML parsing error.
|
||||
*/
|
||||
Node[] loadAll(Stream input, in string name = "<unknown>")
|
||||
{
|
||||
auto loader = Loader(input, name, new Constructor, new Resolver);
|
||||
Node[] result;
|
||||
foreach(ref node; loader){result ~= node;}
|
||||
return result;
|
||||
}
|
||||
|
||||
///Loads YAML documents from files or streams.
|
||||
struct Loader
|
||||
{
|
||||
private:
|
||||
///Reads character data from a stream.
|
||||
Reader reader_;
|
||||
///Processes character data to YAML tokens.
|
||||
Scanner scanner_;
|
||||
///Processes tokens to YAML events.
|
||||
Parser parser_;
|
||||
///Resolves tags (data types).
|
||||
Resolver resolver_;
|
||||
///Constructs YAML data types.
|
||||
Constructor constructor_;
|
||||
///Composes YAML nodes.
|
||||
Composer composer_;
|
||||
///Name of the input file or stream, used in error messages.
|
||||
string name_;
|
||||
///Input file stream, if the stream is created by Loader itself.
|
||||
File file_ = null;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a Loader to load YAML from a file.
|
||||
*
|
||||
* Params: filename = Name of the file to load from.
|
||||
*
|
||||
* Throws: YAMLException if the file could not be opened or read from.
|
||||
*/
|
||||
this(in string filename)
|
||||
{
|
||||
try{file_ = new File(filename);}
|
||||
catch(StreamException e)
|
||||
{
|
||||
throw new YAMLException("Unable to load YAML file " ~ filename ~ " : " ~ e.msg);
|
||||
}
|
||||
this(file_, filename, new Constructor, new Resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Loader to load YAML from a file, with provided _constructor and _resolver.
|
||||
*
|
||||
* Constructor and _resolver can be used to implement custom data types in YAML.
|
||||
*
|
||||
* Params: filename = Name of the file to load from.
|
||||
* constructor = Constructor to use.
|
||||
* resolver = Resolver to use.
|
||||
*
|
||||
* Throws: YAMLException if the file could not be opened or read from.
|
||||
*/
|
||||
this(in string filename, Constructor constructor, Resolver resolver)
|
||||
{
|
||||
try{file_ = new File(filename);}
|
||||
catch(StreamException e)
|
||||
{
|
||||
throw new YAMLException("Unable to load YAML file " ~ filename ~ " : " ~ e.msg);
|
||||
}
|
||||
|
||||
this(file_, filename, constructor, resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Loader to load YAML from a stream with provided _constructor and _resolver.
|
||||
*
|
||||
* Stream can be used to load YAML from memory and other sources.
|
||||
* Constructor and _resolver can be used to implement custom data types in YAML.
|
||||
*
|
||||
* Params: input = Stream to read from. Must be readable.
|
||||
* name = Name of the stream. Used in error messages.
|
||||
* constructor = Constructor to use.
|
||||
* resolver = Resolver to use.
|
||||
*
|
||||
* Throws: YAMLException if the stream could not be read from.
|
||||
*/
|
||||
this(Stream input, in string name, Constructor constructor, Resolver resolver)
|
||||
{
|
||||
try
|
||||
{
|
||||
reader_ = new Reader(input);
|
||||
scanner_ = new Scanner(reader_);
|
||||
parser_ = new Parser(scanner_);
|
||||
resolver_ = resolver;
|
||||
constructor_ = constructor;
|
||||
composer_ = new Composer(parser_, resolver_, constructor_);
|
||||
name_ = name;
|
||||
}
|
||||
catch(YAMLException e)
|
||||
{
|
||||
e.name = name_;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load single YAML document.
|
||||
*
|
||||
* If no or more than one YAML document is found, this will throw a YAMLException.
|
||||
*
|
||||
* Returns: Root node of the document.
|
||||
*
|
||||
* Throws: YAMLException if there wasn't exactly one document
|
||||
* or on a YAML parsing error.
|
||||
*/
|
||||
Node loadSingleDocument()
|
||||
{
|
||||
try
|
||||
{
|
||||
enforce(composer_.checkNode(), new YAMLException("No YAML document to load"));
|
||||
return composer_.getSingleNode();
|
||||
}
|
||||
catch(YAMLException e)
|
||||
{
|
||||
e.name = name_;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Foreach over YAML documents.
|
||||
*
|
||||
* Parses documents lazily, as they are needed.
|
||||
*
|
||||
* Throws: YAMLException on a parsing error.
|
||||
*/
|
||||
int opApply(int delegate(ref Node) dg)
|
||||
{
|
||||
try
|
||||
{
|
||||
int result = 0;
|
||||
while(composer_.checkNode())
|
||||
{
|
||||
auto node = composer_.getNode();
|
||||
result = dg(node);
|
||||
if(result){break;}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch(YAMLException e)
|
||||
{
|
||||
e.name = name_;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
///Destroy the Loader.
|
||||
~this()
|
||||
{
|
||||
clear(reader_);
|
||||
clear(scanner_);
|
||||
clear(parser_);
|
||||
clear(composer_);
|
||||
//Can't clear constructor, resolver: they might be supplied by the user.
|
||||
if(file_ !is null){file_.close();}
|
||||
}
|
||||
|
||||
package:
|
||||
//Scan and return all tokens. Used for debugging.
|
||||
Token[] scan()
|
||||
{
|
||||
try
|
||||
{
|
||||
Token[] result;
|
||||
while(scanner_.checkToken()){result ~= scanner_.getToken();}
|
||||
return result;
|
||||
}
|
||||
catch(YAMLException e)
|
||||
{
|
||||
e.name = name_;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
//Parse and return all events. Used for debugging.
|
||||
Event[] parse()
|
||||
{
|
||||
try
|
||||
{
|
||||
Event[] result;
|
||||
while(parser_.checkEvent()){result ~= parser_.getEvent();}
|
||||
return result;
|
||||
}
|
||||
catch(YAMLException e)
|
||||
{
|
||||
e.name = name_;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
720
dyaml/node.d
Normal file
|
@ -0,0 +1,720 @@
|
|||
|
||||
// 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.
|
||||
*/
|
||||
module dyaml.node;
|
||||
|
||||
|
||||
import std.algorithm;
|
||||
import std.conv;
|
||||
import std.datetime;
|
||||
import std.exception;
|
||||
import std.math;
|
||||
import std.stdio;
|
||||
import std.traits;
|
||||
import std.typecons;
|
||||
import std.variant;
|
||||
|
||||
import dyaml.event;
|
||||
import dyaml.exception;
|
||||
|
||||
|
||||
///Exception thrown at node related errors.
|
||||
class NodeException : YAMLException
|
||||
{
|
||||
package:
|
||||
/*
|
||||
* Construct a NodeException.
|
||||
*
|
||||
* Params: msg = Error message.
|
||||
* start = Start position of the node.
|
||||
* end = End position of the node.
|
||||
*/
|
||||
this(string msg, Mark start, Mark end)
|
||||
{
|
||||
super(msg ~ "\nstart:" ~ start.toString() ~ "\nend:" ~ end.toString());
|
||||
}
|
||||
}
|
||||
|
||||
//Node kinds.
|
||||
package enum NodeID : ubyte
|
||||
{
|
||||
Scalar,
|
||||
Sequence,
|
||||
Mapping
|
||||
}
|
||||
|
||||
///Null YAML type. Used in nodes with _null values.
|
||||
struct YAMLNull{}
|
||||
|
||||
//Merge YAML type, used to support "tag:yaml.org,2002:merge".
|
||||
package struct YAMLMerge{}
|
||||
|
||||
///Base class for YAMLContainer - used for user defined YAML types.
|
||||
private abstract class YAMLObject
|
||||
{
|
||||
protected:
|
||||
///Get type of the stored value.
|
||||
@property TypeInfo type() const;
|
||||
|
||||
///Test for equality with another YAMLObject.
|
||||
bool equals(YAMLObject rhs);
|
||||
}
|
||||
|
||||
//Stores a user defined YAML data type.
|
||||
private class YAMLContainer(T) : YAMLObject
|
||||
{
|
||||
private:
|
||||
//Stored value.
|
||||
T value_;
|
||||
|
||||
//Construct a YAMLContainer holding specified value.
|
||||
this(T value){value_ = value;}
|
||||
|
||||
protected:
|
||||
//Get type of the stored value.
|
||||
@property override TypeInfo type() const {return typeid(T);}
|
||||
|
||||
//Test for equality with another YAMLObject.
|
||||
override bool equals(YAMLObject rhs)
|
||||
{
|
||||
if(rhs.type !is typeid(T)){return false;}
|
||||
return value_ == (cast(YAMLContainer)rhs).value_;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* YAML node.
|
||||
*
|
||||
* This is a pseudo-dynamic type that can store any YAML value, including sequence
|
||||
* or a mapping of nodes. You can get data from a Node directly or iterate over it
|
||||
* if it's a sequence or a mapping.
|
||||
*/
|
||||
struct Node
|
||||
{
|
||||
|
||||
public:
|
||||
///Pair of YAML nodes, used in mappings.
|
||||
struct Pair
|
||||
{
|
||||
///Key node.
|
||||
Node key;
|
||||
///Value node.
|
||||
Node value;
|
||||
|
||||
///Test for equality with another Pair.
|
||||
bool equals(ref Pair rhs)
|
||||
{
|
||||
return key == rhs.key && value == rhs.value;
|
||||
}
|
||||
}
|
||||
package:
|
||||
//YAML value type.
|
||||
alias Algebraic!(YAMLNull, YAMLMerge, bool, long, real, ubyte[], SysTime, string,
|
||||
Node.Pair[], Node[], YAMLObject) Value;
|
||||
|
||||
//Stored value.
|
||||
Value value_;
|
||||
|
||||
private:
|
||||
///Start position of the node.
|
||||
Mark startMark_;
|
||||
///End position of the node.
|
||||
Mark endMark_;
|
||||
|
||||
public:
|
||||
///Is this node valid (initialized)?
|
||||
@property bool isValid() const {return value_.hasValue;}
|
||||
|
||||
///Is this node a scalar value?
|
||||
@property bool isScalar() const {return !(isMapping || isSequence);}
|
||||
|
||||
///Is this node a sequence of nodes?
|
||||
@property bool isSequence() const {return isType!(Node[]);}
|
||||
|
||||
///Is this node a mapping of nodes?
|
||||
@property bool isMapping() const {return isType!(Pair[]);}
|
||||
|
||||
///Is this node a user defined type?
|
||||
@property bool isUserType() const {return isType!YAMLObject;}
|
||||
|
||||
/**
|
||||
* Equality test.
|
||||
*
|
||||
* If T is Node, recursively compare all
|
||||
* subnodes and might be quite expensive if testing entire documents.
|
||||
*
|
||||
* If T is not Node, convert the node to T and test equality with that.
|
||||
*
|
||||
* Examples:
|
||||
* --------------------
|
||||
* //node is a Node that contains integer 42
|
||||
* assert(node == 42);
|
||||
* assert(node == "42");
|
||||
* assert(node != "43");
|
||||
* --------------------
|
||||
*
|
||||
* Params: rhs = Variable to test equality with.
|
||||
*
|
||||
* Returns: true if equal, false otherwise.
|
||||
*/
|
||||
bool opEquals(T)(ref T rhs)
|
||||
{
|
||||
static if(is(T == Node))
|
||||
{
|
||||
if(!isValid){return !rhs.isValid;}
|
||||
if(!rhs.isValid || (value_.type !is rhs.value_.type))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(isSequence)
|
||||
{
|
||||
auto seq1 = get!(Node[]);
|
||||
auto seq2 = rhs.get!(Node[]);
|
||||
if(seq1.length != seq2.length){return false;}
|
||||
foreach(node; 0 .. seq1.length)
|
||||
{
|
||||
if(seq1[node] != seq2[node]){return false;}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(isMapping)
|
||||
{
|
||||
auto map1 = get!(Node.Pair[]);
|
||||
auto map2 = rhs.get!(Node.Pair[]);
|
||||
if(map1.length != map2.length){return false;}
|
||||
foreach(pair; 0 .. map1.length)
|
||||
{
|
||||
if(!map1[pair].equals(map2[pair])){return false;}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(isScalar)
|
||||
{
|
||||
if(isUserType)
|
||||
{
|
||||
if(!rhs.isUserType){return false;}
|
||||
return get!YAMLObject.equals(rhs.get!YAMLObject);
|
||||
}
|
||||
if(isFloat)
|
||||
{
|
||||
if(!rhs.isFloat){return false;}
|
||||
real r1 = get!real;
|
||||
real r2 = rhs.get!real;
|
||||
if(isNaN(r1)){return isNaN(r2);}
|
||||
return r1 == r2;
|
||||
}
|
||||
else{return value_ == rhs.value_;}
|
||||
}
|
||||
assert(false, "Unknown kind of node");
|
||||
}
|
||||
else
|
||||
{
|
||||
try{return rhs == get!T;}
|
||||
catch(NodeException e){return false;}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the node as specified type.
|
||||
*
|
||||
* If the specifed type does not match type in the node,
|
||||
* conversion is attempted if possible.
|
||||
*
|
||||
* Timestamps are stored as std.datetime.SysTime.
|
||||
* Binary values are decoded and stored as ubyte[].
|
||||
*
|
||||
* $(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 expects the node to be a scalar.
|
||||
* )
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* Automatic type conversion:
|
||||
* --------------------
|
||||
* //node is a node that contains integer 42
|
||||
* assert(node.get!int == 42);
|
||||
* assert(node.get!string == "42");
|
||||
* assert(node.get!double == 42.0);
|
||||
* --------------------
|
||||
*
|
||||
* Returns: Value of the node as specified type.
|
||||
*
|
||||
* Throws: NodeException if unable to convert to specified type.
|
||||
*/
|
||||
@property T get(T)()
|
||||
{
|
||||
T result;
|
||||
getToVar(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the value of the node to target.
|
||||
*
|
||||
* If the type of target does not match type of the node,
|
||||
* conversion is attempted, if possible.
|
||||
*
|
||||
* Params: target = Variable to write to.
|
||||
*
|
||||
* Throws: NodeException if unable to convert to specified type.
|
||||
*/
|
||||
void getToVar(T)(out T target)
|
||||
{
|
||||
if(isType!T)
|
||||
{
|
||||
target = value_.get!T;
|
||||
return;
|
||||
}
|
||||
|
||||
///Must go before others, as even string/int/etc could be stored in a YAMLObject.
|
||||
if(isUserType)
|
||||
{
|
||||
auto object = get!YAMLObject;
|
||||
if(object.type is typeid(T))
|
||||
{
|
||||
target = (cast(YAMLContainer!T)object).value_;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//If we're getting from a mapping and we're not getting Node.Pair[],
|
||||
//we're getting the default value.
|
||||
if(isMapping){return this["="].get!T;}
|
||||
|
||||
static if(isSomeString!T)
|
||||
{
|
||||
//Try to convert to string.
|
||||
try
|
||||
{
|
||||
target = value_.coerce!T();
|
||||
return;
|
||||
}
|
||||
catch(VariantException e)
|
||||
{
|
||||
throw new NodeException("Unable to convert node value to a string",
|
||||
startMark_, endMark_);
|
||||
}
|
||||
}
|
||||
else static if(isFloatingPoint!T)
|
||||
{
|
||||
///Can convert int to float.
|
||||
if(isInt())
|
||||
{
|
||||
target = to!T(value_.get!long);
|
||||
return;
|
||||
}
|
||||
else if(isFloat())
|
||||
{
|
||||
target = to!T(value_.get!real);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else static if(isIntegral!T)
|
||||
{
|
||||
if(isInt())
|
||||
{
|
||||
long temp = value_.get!long;
|
||||
if(temp < T.min || temp > T.max)
|
||||
{
|
||||
throw new NodeException("Integer value out of range of type " ~
|
||||
typeid(T).toString ~ "Value: " ~
|
||||
to!string(temp), startMark_, endMark_);
|
||||
}
|
||||
target = to!T(temp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Can't get the value.
|
||||
throw new NodeException("Node has unexpected type " ~ value_.type.toString ~
|
||||
". Expected " ~ typeid(T).toString, startMark_, endMark_);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is a sequence or a mapping, 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()
|
||||
{
|
||||
if(isSequence) {return get!(Node[]).length;}
|
||||
else if(isMapping){return get!(Pair[]).length;}
|
||||
throw new NodeException("Trying to get length of a node that is not a collection",
|
||||
startMark_, endMark_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element with 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, even after conversion. I.e; node["12"] will
|
||||
* return value of the first key that equals "12", even if it's an integer.
|
||||
*
|
||||
* Params: index = Index to use.
|
||||
*
|
||||
* Returns: Value corresponding to the index.
|
||||
*
|
||||
* Throws: NodeException if the index could not be found.
|
||||
*/
|
||||
Node opIndex(T)(in T index)
|
||||
{
|
||||
if(isSequence)
|
||||
{
|
||||
//Sequence, index must be integral.
|
||||
static if(isIntegral!T)
|
||||
{
|
||||
auto nodes = value_.get!(Node[]);
|
||||
enforce(index >= 0 && index < nodes.length,
|
||||
new NodeException("Index to a sequence out of range: "
|
||||
~ to!string(index), startMark_, endMark_));
|
||||
return nodes[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NodeException("Indexing a sequence with a non-integer type.",
|
||||
startMark_, endMark_);
|
||||
}
|
||||
}
|
||||
else if(isMapping)
|
||||
{
|
||||
//Mapping, look for keys convertible to T with value of index.
|
||||
foreach(ref pair; get!(Pair[]))
|
||||
{
|
||||
//Handle NaN.
|
||||
static if(isFloatingPoint!T)
|
||||
{
|
||||
if(isFloat && isNaN(index) && isNaN(pair.key.get!real))
|
||||
{
|
||||
return pair.value;
|
||||
}
|
||||
}
|
||||
//If we can get the key as type T, get it and compare to
|
||||
//index, and return value if the key matches.
|
||||
if(pair.key.convertsTo!T && pair.key.get!T == index)
|
||||
{
|
||||
return pair.value;
|
||||
}
|
||||
}
|
||||
throw new NodeException("Mapping index not found" ~
|
||||
isSomeString!T ? ": " ~ to!string(index) : "",
|
||||
startMark_, endMark_);
|
||||
}
|
||||
throw new NodeException("Trying to index node that does not support indexing",
|
||||
startMark_, endMark_);
|
||||
}
|
||||
unittest
|
||||
{
|
||||
writeln("D:YAML Node opIndex unittest");
|
||||
|
||||
alias Node.Value Value;
|
||||
alias Node.Pair Pair;
|
||||
Node n1 = Node(Value(cast(long)11));
|
||||
Node n2 = Node(Value(cast(long)12));
|
||||
Node n3 = Node(Value(cast(long)13));
|
||||
Node n4 = Node(Value(cast(long)14));
|
||||
|
||||
Node k1 = Node(Value("11"));
|
||||
Node k2 = Node(Value("12"));
|
||||
Node k3 = Node(Value("13"));
|
||||
Node k4 = Node(Value("14"));
|
||||
|
||||
Node narray = Node(Value([n1, n2, n3, n4]));
|
||||
Node nmap = Node(Value([Pair(k1, n1),
|
||||
Pair(k2, n2),
|
||||
Pair(k3, n3),
|
||||
Pair(k4, n4)]));
|
||||
|
||||
assert(narray[0].get!int == 11);
|
||||
assert(null !is collectException(narray[42]));
|
||||
assert(nmap["11"].get!int == 11);
|
||||
assert(nmap["14"].get!int == 14);
|
||||
assert(null !is collectException(nmap["42"]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate 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(T)(int delegate(ref T) dg)
|
||||
{
|
||||
enforce(isSequence,
|
||||
new NodeException("Trying to iterate over a node that is not a sequence",
|
||||
startMark_, endMark_));
|
||||
|
||||
int result = 0;
|
||||
foreach(ref node; get!(Node[]))
|
||||
{
|
||||
static if(is(T == Node))
|
||||
{
|
||||
result = dg(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
T temp = node.get!T;
|
||||
result = dg(temp);
|
||||
}
|
||||
if(result){break;}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
unittest
|
||||
{
|
||||
writeln("D:YAML Node opApply unittest 1");
|
||||
|
||||
alias Node.Value Value;
|
||||
alias Node.Pair Pair;
|
||||
|
||||
Node n1 = Node(Value(cast(long)11));
|
||||
Node n2 = Node(Value(cast(long)12));
|
||||
Node n3 = Node(Value(cast(long)13));
|
||||
Node n4 = Node(Value(cast(long)14));
|
||||
Node narray = Node(Value([n1, n2, n3, n4]));
|
||||
|
||||
int[] array, array2;
|
||||
foreach(int value; narray)
|
||||
{
|
||||
array ~= value;
|
||||
}
|
||||
foreach(Node node; narray)
|
||||
{
|
||||
array2 ~= node.get!int;
|
||||
}
|
||||
assert(array == [11, 12, 13, 14]);
|
||||
assert(array2 == [11, 12, 13, 14]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate 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(K, V)(int delegate(ref K, ref V) dg)
|
||||
{
|
||||
enforce(isMapping,
|
||||
new NodeException("Trying to iterate over a node that is not a mapping",
|
||||
startMark_, endMark_));
|
||||
|
||||
int result = 0;
|
||||
foreach(ref pair; get!(Node.Pair[]))
|
||||
{
|
||||
static if(is(K == Node) && is(V == Node))
|
||||
{
|
||||
result = dg(pair.key, pair.value);
|
||||
}
|
||||
else static if(is(K == Node))
|
||||
{
|
||||
V tempValue = pair.value.get!V;
|
||||
result = dg(pair.key, tempValue);
|
||||
}
|
||||
else static if(is(V == Node))
|
||||
{
|
||||
K tempKey = pair.key.get!K;
|
||||
result = dg(tempKey, pair.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
K tempKey = pair.key.get!K;
|
||||
V tempValue = pair.value.get!V;
|
||||
result = dg(tempKey, tempValue);
|
||||
}
|
||||
|
||||
if(result){break;}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
unittest
|
||||
{
|
||||
writeln("D:YAML Node opApply unittest 2");
|
||||
|
||||
alias Node.Value Value;
|
||||
alias Node.Pair Pair;
|
||||
|
||||
Node n1 = Node(Value(cast(long)11));
|
||||
Node n2 = Node(Value(cast(long)12));
|
||||
Node n3 = Node(Value(cast(long)13));
|
||||
Node n4 = Node(Value(cast(long)14));
|
||||
|
||||
Node k1 = Node(Value("11"));
|
||||
Node k2 = Node(Value("12"));
|
||||
Node k3 = Node(Value("13"));
|
||||
Node k4 = Node(Value("14"));
|
||||
|
||||
Node nmap1 = Node(Value([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(Value([Pair(k1, Node(Value(cast(long)5))),
|
||||
Pair(k2, Node(Value(true))),
|
||||
Pair(k3, Node(Value(cast(real)1.0))),
|
||||
Pair(k4, Node(Value("yarly")))]));
|
||||
|
||||
foreach(string key, Node value; nmap2)
|
||||
{
|
||||
switch(key)
|
||||
{
|
||||
case "11": assert(value.get!int == 5 ); break;
|
||||
case "12": assert(value.get!bool == true ); break;
|
||||
case "13": assert(value.get!float == 1.0 ); break;
|
||||
case "14": assert(value.get!string == "yarly"); break;
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
string indent;
|
||||
foreach(i; 0 .. level){indent ~= " ";}
|
||||
|
||||
if(!isValid){return indent ~ "invalid";}
|
||||
|
||||
if(isSequence)
|
||||
{
|
||||
string result = indent ~ "sequence:\n";
|
||||
foreach(ref node; get!(Node[]))
|
||||
{
|
||||
result ~= node.debugString(level + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if(isMapping)
|
||||
{
|
||||
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;
|
||||
}
|
||||
if(isScalar)
|
||||
{
|
||||
return indent ~ "scalar(" ~
|
||||
(convertsTo!string ? get!string : value_.type.toString) ~ ")\n";
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
//Construct Node.Value from user defined type.
|
||||
static Value userValue(T)(T value)
|
||||
{
|
||||
return Value(cast(YAMLObject)new YAMLContainer!T(value));
|
||||
}
|
||||
|
||||
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(T);}
|
||||
|
||||
///Is the value an integer of some kind?
|
||||
alias isType!long isInt;
|
||||
|
||||
///Is the value a floating point number of some kind?
|
||||
alias isType!real isFloat;
|
||||
|
||||
//Determine if the value can be converted to specified type.
|
||||
bool convertsTo(T)()
|
||||
{
|
||||
if(isType!T){return true;}
|
||||
|
||||
static if(isSomeString!T)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto dummy = value_.coerce!T();
|
||||
return true;
|
||||
}
|
||||
catch(VariantException e){return false;}
|
||||
}
|
||||
else static if(isFloatingPoint!T){return isInt() || isFloat();}
|
||||
else static if(isIntegral!T) {return isInt();}
|
||||
else {return false;}
|
||||
}
|
||||
}
|
||||
|
||||
package:
|
||||
/*
|
||||
* Merge a pair into an array of pairs based on merge rules in the YAML spec.
|
||||
*
|
||||
* The new pair will only be added if there is not already a pair
|
||||
* with the same key.
|
||||
*
|
||||
* Params: pairs = Array of pairs to merge into.
|
||||
* toMerge = Pair to merge.
|
||||
*/
|
||||
void merge(ref Node.Pair[] pairs, ref Node.Pair toMerge)
|
||||
{
|
||||
foreach(ref pair; pairs)
|
||||
{
|
||||
if(pair.key == toMerge.key){return;}
|
||||
}
|
||||
pairs ~= toMerge;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 = Array of pairs to merge into.
|
||||
* toMerge = Pairs to merge.
|
||||
*/
|
||||
void merge(ref Node.Pair[] pairs, Node.Pair[] toMerge)
|
||||
{
|
||||
foreach(ref pair; toMerge){merge(pairs, pair);}
|
||||
}
|
842
dyaml/parser.d
Normal file
|
@ -0,0 +1,842 @@
|
|||
|
||||
// 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 parser.
|
||||
* Code based on PyYAML: http://www.pyyaml.org
|
||||
*/
|
||||
module dyaml.parser;
|
||||
|
||||
|
||||
import std.array;
|
||||
import std.conv;
|
||||
import std.exception;
|
||||
|
||||
import dyaml.event;
|
||||
import dyaml.scanner;
|
||||
import dyaml.token;
|
||||
import dyaml.exception;
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
this(string context, Mark contextMark, string problem, Mark problemMark)
|
||||
{
|
||||
super(context, contextMark, problem, problemMark);
|
||||
}
|
||||
|
||||
this(string problem, Mark problemMark){super(problem, problemMark);}
|
||||
}
|
||||
|
||||
///Generates events from tokens provided by a Scanner.
|
||||
final class Parser
|
||||
{
|
||||
invariant()
|
||||
{
|
||||
assert(currentEvent_.length <= 1);
|
||||
}
|
||||
|
||||
private:
|
||||
///Default tag handle shortcuts and replacements.
|
||||
static string[string] defaultTags_;
|
||||
static this()
|
||||
{
|
||||
defaultTags_ = ["!" : "!", "!!" : "tag:yaml.org,2002:"];
|
||||
}
|
||||
|
||||
///Scanner providing YAML tokens.
|
||||
Scanner scanner_;
|
||||
|
||||
///Holds zero or one event.
|
||||
Event[] currentEvent_;
|
||||
|
||||
///YAML version string.
|
||||
string YAMLVersion_ = null;
|
||||
///Tag handle shortcuts and replacements.
|
||||
string[string] tagHandles_;
|
||||
|
||||
///Stack of states.
|
||||
Event delegate()[] states_;
|
||||
///Stack of marks used to keep track of extents of e.g. YAML collections.
|
||||
Mark[] marks_;
|
||||
///Current state.
|
||||
Event delegate() state_;
|
||||
|
||||
public:
|
||||
///Construct a Parser using specified Scanner.
|
||||
this(Scanner scanner)
|
||||
{
|
||||
state_ = &parseStreamStart;
|
||||
scanner_ = scanner;
|
||||
}
|
||||
|
||||
///Destroy the parser.
|
||||
~this()
|
||||
{
|
||||
clear(currentEvent_);
|
||||
currentEvent_ = null;
|
||||
clear(tagHandles_);
|
||||
tagHandles_ = null;
|
||||
clear(states_);
|
||||
states_ = null;
|
||||
clear(marks_);
|
||||
marks_ = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the next event is one of specified types.
|
||||
*
|
||||
* If no types are specified, checks if any events are left.
|
||||
*
|
||||
* Params: ids = Event IDs to check for.
|
||||
*
|
||||
* Returns: true if the next event is one of specified types,
|
||||
* or if there are any events left if no types specified.
|
||||
* false otherwise.
|
||||
*/
|
||||
bool checkEvent(EventID[] ids...)
|
||||
{
|
||||
//Check if the next event is one of specified types.
|
||||
if(currentEvent_.empty && state_ !is null)
|
||||
{
|
||||
currentEvent_ ~= state_();
|
||||
}
|
||||
|
||||
if(!currentEvent_.empty)
|
||||
{
|
||||
if(ids.length == 0){return true;}
|
||||
else
|
||||
{
|
||||
const nextId = currentEvent_.front.id;
|
||||
foreach(id; ids)
|
||||
{
|
||||
if(nextId == id){return true;}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next event, but keep it in the queue.
|
||||
*
|
||||
* Must not be called if there are no events left.
|
||||
*/
|
||||
Event peekEvent()
|
||||
{
|
||||
if(currentEvent_.empty && state_ !is null)
|
||||
{
|
||||
currentEvent_ ~= state_();
|
||||
}
|
||||
if(!currentEvent_.empty){return currentEvent_[0];}
|
||||
assert(false, "No event left to peek");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next event, removing it from the queue.
|
||||
*
|
||||
* Must not be called if there are no events left.
|
||||
*/
|
||||
Event getEvent()
|
||||
{
|
||||
//Get the next event and proceed further.
|
||||
if(currentEvent_.empty && state_ !is null)
|
||||
{
|
||||
currentEvent_ ~= state_();
|
||||
}
|
||||
|
||||
if(!currentEvent_.empty)
|
||||
{
|
||||
Event result = currentEvent_[0];
|
||||
currentEvent_.length = 0;
|
||||
return result;
|
||||
}
|
||||
assert(false, "No event left to get");
|
||||
}
|
||||
|
||||
private:
|
||||
///Pop and return the newest state in states_.
|
||||
Event delegate() popState()
|
||||
{
|
||||
enforce(states_.length > 0,
|
||||
new YAMLException("Parser: Need to pop a state but there are no states left"));
|
||||
const result = states_.back();
|
||||
states_.popBack;
|
||||
return result;
|
||||
}
|
||||
|
||||
///Pop and return the newest mark in marks_.
|
||||
Mark popMark()
|
||||
{
|
||||
enforce(marks_.length > 0,
|
||||
new YAMLException("Parser: Need to pop a mark but there are no marks left"));
|
||||
const result = marks_.back();
|
||||
marks_.popBack;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
Token token = scanner_.getToken();
|
||||
state_ = &parseImplicitDocumentStart;
|
||||
return streamStartEvent(token.startMark, token.endMark);
|
||||
}
|
||||
|
||||
///Parse implicit document start, unless explicit is detected: if so, parse explicit.
|
||||
Event parseImplicitDocumentStart()
|
||||
{
|
||||
//Parse an implicit document.
|
||||
if(!scanner_.checkToken(TokenID.Directive, TokenID.DocumentStart,
|
||||
TokenID.StreamEnd))
|
||||
{
|
||||
tagHandles_ = defaultTags_;
|
||||
Token token = scanner_.peekToken();
|
||||
|
||||
states_ ~= &parseDocumentEnd;
|
||||
state_ = &parseBlockNode;
|
||||
|
||||
return documentStartEvent(token.startMark, token.endMark, false, null);
|
||||
}
|
||||
return parseDocumentStart();
|
||||
}
|
||||
|
||||
///Parse explicit document start.
|
||||
Event parseDocumentStart()
|
||||
{
|
||||
//Parse any extra document end indicators.
|
||||
while(scanner_.checkToken(TokenID.DocumentEnd)){scanner_.getToken();}
|
||||
|
||||
//Parse an explicit document.
|
||||
if(!scanner_.checkToken(TokenID.StreamEnd))
|
||||
{
|
||||
const startMark = scanner_.peekToken().startMark;
|
||||
|
||||
processDirectives();
|
||||
enforce(scanner_.checkToken(TokenID.DocumentStart),
|
||||
new ParserException("Expected document start but found " ~
|
||||
to!string(scanner_.peekToken().id),
|
||||
scanner_.peekToken().startMark));
|
||||
|
||||
const endMark = scanner_.getToken().endMark;
|
||||
states_ ~= &parseDocumentEnd;
|
||||
state_ = &parseDocumentContent;
|
||||
return documentStartEvent(startMark, endMark, true, YAMLVersion_);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Parse the end of the stream.
|
||||
Token token = scanner_.getToken();
|
||||
assert(states_.length == 0);
|
||||
assert(marks_.length == 0);
|
||||
state_ = null;
|
||||
return streamEndEvent(token.startMark, token.endMark);
|
||||
}
|
||||
}
|
||||
|
||||
///Parse document end (explicit or implicit).
|
||||
Event parseDocumentEnd()
|
||||
{
|
||||
Mark startMark = scanner_.peekToken().startMark;
|
||||
const bool explicit = scanner_.checkToken(TokenID.DocumentEnd);
|
||||
Mark endMark = explicit ? scanner_.getToken().endMark : startMark;
|
||||
|
||||
state_ = &parseDocumentStart;
|
||||
|
||||
return documentEndEvent(startMark, endMark, explicit);
|
||||
}
|
||||
|
||||
///Parse document content.
|
||||
Event parseDocumentContent()
|
||||
{
|
||||
if(scanner_.checkToken(TokenID.Directive, TokenID.DocumentStart,
|
||||
TokenID.DocumentEnd, TokenID.StreamEnd))
|
||||
{
|
||||
state_ = popState();
|
||||
return processEmptyScalar(scanner_.peekToken().startMark);
|
||||
}
|
||||
return parseBlockNode();
|
||||
}
|
||||
|
||||
///Process directives at the beginning of a document.
|
||||
void processDirectives()
|
||||
{
|
||||
//Destroy version and tag handles from previous document.
|
||||
YAMLVersion_ = null;
|
||||
string[string] empty;
|
||||
tagHandles_ = empty;
|
||||
|
||||
//Process directives.
|
||||
while(scanner_.checkToken(TokenID.Directive))
|
||||
{
|
||||
Token token = scanner_.getToken();
|
||||
//Name and value are separated by '\0'.
|
||||
const parts = token.value.split("\0");
|
||||
const name = parts[0];
|
||||
if(name == "YAML")
|
||||
{
|
||||
enforce(YAMLVersion_ is null,
|
||||
new ParserException("Found duplicate YAML directive",
|
||||
token.startMark));
|
||||
const minor = parts[1].split(".")[0];
|
||||
enforce(to!int(minor) == 1,
|
||||
new ParserException("Found incompatible YAML document (version "
|
||||
"1.* is required)", token.startMark));
|
||||
YAMLVersion_ = parts[1];
|
||||
}
|
||||
else if(name == "TAG")
|
||||
{
|
||||
assert(parts.length == 3, "Tag directive stored incorrectly in a token");
|
||||
const handle = parts[1];
|
||||
|
||||
foreach(h, replacement; tagHandles_)
|
||||
{
|
||||
enforce(h != handle, new ParserException("Duplicate tag handle: " ~
|
||||
handle, token.startMark));
|
||||
}
|
||||
tagHandles_[handle] = parts[2];
|
||||
}
|
||||
}
|
||||
|
||||
//Add any default tag handles that haven't been overridden.
|
||||
foreach(key, value; defaultTags_)
|
||||
{
|
||||
if((key in tagHandles_) is null){tagHandles_[key] = 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(bool block, bool indentlessSequence = false)
|
||||
{
|
||||
if(scanner_.checkToken(TokenID.Alias))
|
||||
{
|
||||
Token token = scanner_.getToken();
|
||||
state_ = popState();
|
||||
return aliasEvent(token.startMark, token.endMark, token.value);
|
||||
}
|
||||
|
||||
string anchor = null;
|
||||
string tag = null;
|
||||
Mark startMark, endMark, tagMark;
|
||||
bool invalidMarks = true;
|
||||
|
||||
//Get anchor/tag if detected. Return false otherwise.
|
||||
bool get(TokenID id, bool start, ref string target)
|
||||
{
|
||||
if(!scanner_.checkToken(id)){return false;}
|
||||
invalidMarks = false;
|
||||
Token token = scanner_.getToken();
|
||||
if(start){startMark = token.startMark;}
|
||||
if(id == TokenID.Tag){tagMark = token.startMark;}
|
||||
endMark = token.endMark;
|
||||
target = token.value;
|
||||
return true;
|
||||
}
|
||||
|
||||
//Anchor and/or tag can be in any order.
|
||||
if(get(TokenID.Anchor, true, anchor)){get(TokenID.Tag, false, tag);}
|
||||
else if(get(TokenID.Tag, true, tag)) {get(TokenID.Anchor, false, anchor);}
|
||||
|
||||
if(tag !is null){tag = processTag(tag, startMark, tagMark);}
|
||||
|
||||
if(invalidMarks)
|
||||
{
|
||||
startMark = endMark = scanner_.peekToken().startMark;
|
||||
}
|
||||
|
||||
bool implicit = (tag is null || tag == "!");
|
||||
|
||||
if(indentlessSequence && scanner_.checkToken(TokenID.BlockEntry))
|
||||
{
|
||||
state_ = &parseIndentlessSequenceEntry;
|
||||
return sequenceStartEvent(startMark, scanner_.peekToken().endMark,
|
||||
anchor, tag, implicit);
|
||||
}
|
||||
|
||||
if(scanner_.checkToken(TokenID.Scalar))
|
||||
{
|
||||
Token token = scanner_.getToken();
|
||||
|
||||
//PyYAML uses a Tuple!(bool, bool) here, but the second bool
|
||||
//is never used after that - so we don't use it.
|
||||
implicit = (token.style == ScalarStyle.Plain && tag is null) || tag == "!";
|
||||
state_ = popState();
|
||||
return scalarEvent(startMark, token.endMark, anchor, tag,
|
||||
implicit, token.value, token.style);
|
||||
}
|
||||
|
||||
if(scanner_.checkToken(TokenID.FlowSequenceStart))
|
||||
{
|
||||
endMark = scanner_.peekToken().endMark;
|
||||
state_ = &parseFlowSequenceEntry!true;
|
||||
return sequenceStartEvent(startMark, endMark, anchor, tag, implicit);
|
||||
}
|
||||
|
||||
if(scanner_.checkToken(TokenID.FlowMappingStart))
|
||||
{
|
||||
endMark = scanner_.peekToken().endMark;
|
||||
state_ = &parseFlowMappingKey!true;
|
||||
return mappingStartEvent(startMark, endMark, anchor, tag, implicit);
|
||||
}
|
||||
|
||||
if(block && scanner_.checkToken(TokenID.BlockSequenceStart))
|
||||
{
|
||||
endMark = scanner_.peekToken().endMark;
|
||||
state_ = &parseBlockSequenceEntry!true;
|
||||
return sequenceStartEvent(startMark, endMark, anchor, tag, implicit);
|
||||
}
|
||||
|
||||
if(block && scanner_.checkToken(TokenID.BlockMappingStart))
|
||||
{
|
||||
endMark = scanner_.peekToken().endMark;
|
||||
state_ = &parseBlockMappingKey!true;
|
||||
return mappingStartEvent(startMark, endMark, anchor, tag, implicit);
|
||||
}
|
||||
|
||||
if(anchor != 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 , "");
|
||||
}
|
||||
|
||||
Token token = scanner_.peekToken();
|
||||
throw new ParserException("While parsing a " ~ (block ? "block" : "flow") ~ " node",
|
||||
startMark, "expected the node content, but found: "
|
||||
~ to!string(token.id), token.startMark);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a tag string retrieved from a tag token.
|
||||
*
|
||||
* Params: tag = Tag before processing.
|
||||
* startMark = Position of the node the tag belongs to.
|
||||
* tagMark = Position of the tag.
|
||||
*/
|
||||
string processTag(in string tag, in Mark startMark, in Mark tagMark)
|
||||
{
|
||||
//Tag handle and suffix are separated by '\0'.
|
||||
const parts = tag.split("\0");
|
||||
assert(parts.length == 2, "Tag data stored incorrectly in a token");
|
||||
const handle = parts[0];
|
||||
const suffix = parts[1];
|
||||
|
||||
if(handle.length > 0)
|
||||
{
|
||||
//handle must be in tagHandles_
|
||||
enforce((handle in tagHandles_) !is null,
|
||||
new ParserException("While parsing a node", startMark,
|
||||
"found undefined tag handle: " ~ handle, tagMark));
|
||||
return tagHandles_[handle] ~ suffix;
|
||||
}
|
||||
return suffix;
|
||||
}
|
||||
|
||||
///Wrappers to parse nodes.
|
||||
Event parseBlockNode(){return parseNode(true);}
|
||||
Event parseFlowNode(){return parseNode(false);}
|
||||
Event parseBlockNodeOrIndentlessSequence(){return parseNode(true, true);}
|
||||
|
||||
///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(bool first)()
|
||||
{
|
||||
static if(first){marks_ ~= scanner_.getToken().startMark;}
|
||||
|
||||
if(scanner_.checkToken(TokenID.BlockEntry))
|
||||
{
|
||||
Token token = scanner_.getToken();
|
||||
if(!scanner_.checkToken(TokenID.BlockEntry, TokenID.BlockEnd))
|
||||
{
|
||||
states_~= &parseBlockSequenceEntry!false;
|
||||
return parseBlockNode();
|
||||
}
|
||||
|
||||
state_ = &parseBlockSequenceEntry!false;
|
||||
return processEmptyScalar(token.endMark);
|
||||
}
|
||||
|
||||
if(!scanner_.checkToken(TokenID.BlockEnd))
|
||||
{
|
||||
Token token = scanner_.peekToken();
|
||||
throw new ParserException("While parsing a block collection", marks_[$ - 1],
|
||||
"expected block end, but found "
|
||||
~ to!string(token.id), token.startMark);
|
||||
}
|
||||
|
||||
state_ = popState();
|
||||
popMark();
|
||||
Token token = scanner_.getToken();
|
||||
return sequenceEndEvent(token.startMark, token.endMark);
|
||||
}
|
||||
|
||||
///indentless_sequence ::= (BLOCK-ENTRY block_node?)+
|
||||
|
||||
///Parse an entry of an indentless sequence.
|
||||
Event parseIndentlessSequenceEntry()
|
||||
{
|
||||
if(scanner_.checkToken(TokenID.BlockEntry))
|
||||
{
|
||||
Token token = scanner_.getToken();
|
||||
|
||||
if(!scanner_.checkToken(TokenID.BlockEntry, TokenID.Key,
|
||||
TokenID.Value, TokenID.BlockEnd))
|
||||
{
|
||||
states_ ~= &parseIndentlessSequenceEntry;
|
||||
return parseBlockNode();
|
||||
}
|
||||
|
||||
state_ = &parseIndentlessSequenceEntry;
|
||||
return processEmptyScalar(token.endMark);
|
||||
}
|
||||
|
||||
state_ = popState();
|
||||
Token token = scanner_.peekToken();
|
||||
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(bool first)()
|
||||
{
|
||||
static if(first){marks_ ~= scanner_.getToken().startMark;}
|
||||
|
||||
if(scanner_.checkToken(TokenID.Key))
|
||||
{
|
||||
Token token = scanner_.getToken();
|
||||
|
||||
if(!scanner_.checkToken(TokenID.Key, TokenID.Value, TokenID.BlockEnd))
|
||||
{
|
||||
states_ ~= &parseBlockMappingValue;
|
||||
return parseBlockNodeOrIndentlessSequence();
|
||||
}
|
||||
|
||||
state_ = &parseBlockMappingValue;
|
||||
return processEmptyScalar(token.endMark);
|
||||
}
|
||||
|
||||
if(!scanner_.checkToken(TokenID.BlockEnd))
|
||||
{
|
||||
Token token = scanner_.peekToken();
|
||||
throw new ParserException("While parsing a block mapping", marks_[$ - 1],
|
||||
"expected block end, but found: "
|
||||
~ to!string(token.id), token.startMark);
|
||||
}
|
||||
|
||||
state_ = popState();
|
||||
popMark();
|
||||
Token token = scanner_.getToken();
|
||||
return mappingEndEvent(token.startMark, token.endMark);
|
||||
}
|
||||
|
||||
///Parse a value in a block mapping.
|
||||
Event parseBlockMappingValue()
|
||||
{
|
||||
if(scanner_.checkToken(TokenID.Value))
|
||||
{
|
||||
Token token = scanner_.getToken();
|
||||
|
||||
if(!scanner_.checkToken(TokenID.Key, TokenID.Value, TokenID.BlockEnd))
|
||||
{
|
||||
states_ ~= &parseBlockMappingKey!false;
|
||||
return parseBlockNodeOrIndentlessSequence();
|
||||
}
|
||||
|
||||
state_ = &parseBlockMappingKey!false;
|
||||
return processEmptyScalar(token.endMark);
|
||||
}
|
||||
|
||||
state_= &parseBlockMappingKey!false;
|
||||
return processEmptyScalar(scanner_.peekToken().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(bool first)()
|
||||
{
|
||||
static if(first){marks_ ~= scanner_.getToken().startMark;}
|
||||
|
||||
if(!scanner_.checkToken(TokenID.FlowSequenceEnd))
|
||||
{
|
||||
static if(!first)
|
||||
{
|
||||
if(scanner_.checkToken(TokenID.FlowEntry))
|
||||
{
|
||||
scanner_.getToken();
|
||||
}
|
||||
else
|
||||
{
|
||||
Token token = scanner_.peekToken;
|
||||
throw new ParserException("While parsing a flow sequence",
|
||||
marks_[$ - 1],
|
||||
"expected ',' or ']', but got: " ~
|
||||
to!string(token.id), token.startMark);
|
||||
}
|
||||
}
|
||||
|
||||
if(scanner_.checkToken(TokenID.Key))
|
||||
{
|
||||
Token token = scanner_.peekToken();
|
||||
state_ = &parseFlowSequenceEntryMappingKey;
|
||||
return mappingStartEvent(token.startMark, token.endMark, null, null, true);
|
||||
}
|
||||
else if(!scanner_.checkToken(TokenID.FlowSequenceEnd))
|
||||
{
|
||||
states_ ~= &parseFlowSequenceEntry!false;
|
||||
return parseFlowNode();
|
||||
}
|
||||
}
|
||||
|
||||
Token token = scanner_.getToken();
|
||||
state_ = popState();
|
||||
popMark();
|
||||
return sequenceEndEvent(token.startMark, token.endMark);
|
||||
}
|
||||
|
||||
///Parse a key in flow context.
|
||||
Event parseFlowKey(in Event delegate() nextState)
|
||||
{
|
||||
Token token = scanner_.getToken();
|
||||
|
||||
if(!scanner_.checkToken(TokenID.Value, TokenID.FlowEntry,
|
||||
TokenID.FlowSequenceEnd))
|
||||
{
|
||||
states_ ~= nextState;
|
||||
return parseFlowNode();
|
||||
}
|
||||
|
||||
state_ = nextState;
|
||||
return processEmptyScalar(token.endMark);
|
||||
}
|
||||
|
||||
///Parse a mapping key in an entry in a flow sequence.
|
||||
Event parseFlowSequenceEntryMappingKey()
|
||||
{
|
||||
return parseFlowKey(&parseFlowSequenceEntryMappingValue);
|
||||
}
|
||||
|
||||
///Parse a mapping value in a flow context.
|
||||
Event parseFlowValue(TokenID checkId, in Event delegate() nextState)
|
||||
{
|
||||
if(scanner_.checkToken(TokenID.Value))
|
||||
{
|
||||
Token token = scanner_.getToken();
|
||||
if(!scanner_.checkToken(TokenID.FlowEntry, checkId))
|
||||
{
|
||||
states_ ~= nextState;
|
||||
return parseFlowNode();
|
||||
}
|
||||
|
||||
state_ = nextState;
|
||||
return processEmptyScalar(token.endMark);
|
||||
}
|
||||
|
||||
state_ = nextState;
|
||||
return processEmptyScalar(scanner_.peekToken().startMark);
|
||||
}
|
||||
|
||||
///Parse a mapping value in an entry in a flow sequence.
|
||||
Event parseFlowSequenceEntryMappingValue()
|
||||
{
|
||||
return parseFlowValue(TokenID.FlowSequenceEnd,
|
||||
&parseFlowSequenceEntryMappingEnd);
|
||||
}
|
||||
|
||||
///Parse end of a mapping in a flow sequence entry.
|
||||
Event parseFlowSequenceEntryMappingEnd()
|
||||
{
|
||||
state_ = &parseFlowSequenceEntry!false;
|
||||
Token token = scanner_.peekToken();
|
||||
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(bool first)()
|
||||
{
|
||||
static if(first){marks_ ~= scanner_.getToken().startMark;}
|
||||
|
||||
if(!scanner_.checkToken(TokenID.FlowMappingEnd))
|
||||
{
|
||||
static if(!first)
|
||||
{
|
||||
if(scanner_.checkToken(TokenID.FlowEntry))
|
||||
{
|
||||
scanner_.getToken();
|
||||
}
|
||||
else
|
||||
{
|
||||
Token token = scanner_.peekToken;
|
||||
throw new ParserException("While parsing a flow mapping",
|
||||
marks_[$ - 1],
|
||||
"expected ',' or '}', but got: " ~
|
||||
to!string(token.id), token.startMark);
|
||||
}
|
||||
}
|
||||
|
||||
if(scanner_.checkToken(TokenID.Key))
|
||||
{
|
||||
return parseFlowKey(&parseFlowMappingValue);
|
||||
}
|
||||
|
||||
if(!scanner_.checkToken(TokenID.FlowMappingEnd))
|
||||
{
|
||||
states_ ~= &parseFlowMappingEmptyValue;
|
||||
return parseFlowNode();
|
||||
}
|
||||
}
|
||||
|
||||
Token token = scanner_.getToken();
|
||||
state_ = popState();
|
||||
popMark();
|
||||
return mappingEndEvent(token.startMark, token.endMark);
|
||||
}
|
||||
|
||||
///Parse a value in a flow mapping.
|
||||
Event parseFlowMappingValue()
|
||||
{
|
||||
return parseFlowValue(TokenID.FlowMappingEnd, &parseFlowMappingKey!false);
|
||||
}
|
||||
|
||||
///Parse an empty value in a flow mapping.
|
||||
Event parseFlowMappingEmptyValue()
|
||||
{
|
||||
state_ = &parseFlowMappingKey!false;
|
||||
return processEmptyScalar(scanner_.peekToken().startMark);
|
||||
}
|
||||
|
||||
///Return an empty scalar.
|
||||
Event processEmptyScalar(in Mark mark)
|
||||
{
|
||||
//PyYAML uses a Tuple!(true, false) for the second last arg here,
|
||||
//but the second bool is never used after that - so we don't use it.
|
||||
return scalarEvent(mark, mark, null, null, true, "");
|
||||
}
|
||||
}
|
482
dyaml/reader.d
Normal file
|
@ -0,0 +1,482 @@
|
|||
|
||||
// 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.reader;
|
||||
|
||||
|
||||
import core.stdc.string;
|
||||
|
||||
import std.algorithm;
|
||||
import std.conv;
|
||||
import std.exception;
|
||||
import std.stdio;
|
||||
import std.stream;
|
||||
import std.string;
|
||||
import std.system;
|
||||
import std.utf;
|
||||
|
||||
import dyaml.exception;
|
||||
|
||||
|
||||
package:
|
||||
|
||||
///Exception thrown at Reader errors.
|
||||
class ReaderException : YAMLException
|
||||
{
|
||||
this(string msg){super("Error reading YAML stream: " ~ msg);}
|
||||
}
|
||||
|
||||
|
||||
///Reads data from a stream and converts it to UTF-32 (dchar) data.
|
||||
final class Reader
|
||||
{
|
||||
private:
|
||||
///Unicode encodings.
|
||||
enum UTF
|
||||
{
|
||||
///UTF-8.
|
||||
_8,
|
||||
///UTF-16.
|
||||
_16,
|
||||
///UTF-32.
|
||||
_32
|
||||
}
|
||||
|
||||
///Input stream.
|
||||
EndianStream stream_;
|
||||
///Buffer of currently loaded characters.
|
||||
dchar[] buffer_;
|
||||
///Current position within buffer. Only data after this position can be read.
|
||||
uint bufferOffset_ = 0;
|
||||
///Index of the current character in the stream.
|
||||
size_t charIndex_ = 0;
|
||||
///Encoding of the input stream.
|
||||
UTF utf_= UTF._8;
|
||||
///Current line in file.
|
||||
uint line_;
|
||||
///Current column in file.
|
||||
uint column_;
|
||||
|
||||
///Capacity of raw buffers.
|
||||
static immutable bufferLength8_ = 8;
|
||||
///Capacity of raw buffers.
|
||||
static immutable bufferLength16_ = bufferLength8_ / 2;
|
||||
|
||||
union
|
||||
{
|
||||
///Buffer to hold UTF-8 data before decoding.
|
||||
char[bufferLength8_] rawBuffer8_;
|
||||
///Buffer to hold UTF-16 data before decoding.
|
||||
wchar[bufferLength16_] rawBuffer16_;
|
||||
}
|
||||
///Number of elements held in the used raw buffer.
|
||||
uint rawUsed_ = 0;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a Reader.
|
||||
*
|
||||
* Params: stream = Input stream. Must be readable.
|
||||
*
|
||||
* Throws: ReaderException if the stream is invalid.
|
||||
*/
|
||||
this(Stream stream)
|
||||
in{assert(stream.readable, "Can't read YAML from a non-readable stream");}
|
||||
body
|
||||
{
|
||||
stream_ = new EndianStream(stream);
|
||||
|
||||
//handle files short enough not to have a BOM
|
||||
if(stream_.available < 2)
|
||||
{
|
||||
utf_ = UTF._8;
|
||||
return;
|
||||
}
|
||||
|
||||
//readBOM will determine and set stream endianness
|
||||
switch(stream_.readBOM(2))
|
||||
{
|
||||
case -1:
|
||||
//readBOM() eats two more bytes in this case so get them back
|
||||
wchar bytes = stream_.getcw();
|
||||
rawBuffer8_[0] = cast(char)(bytes % 256);
|
||||
rawBuffer8_[1] = cast(char)(bytes / 256);
|
||||
rawUsed_ = 2;
|
||||
goto case 0;
|
||||
case 0: utf_ = UTF._8; break;
|
||||
case 1, 2:
|
||||
//readBOM() eats two more bytes in this case so get them back
|
||||
utf_ = UTF._16;
|
||||
rawBuffer16_[0] = stream_.getcw();
|
||||
rawUsed_ = 1;
|
||||
enforce(stream_.available % 2 == 0,
|
||||
new ReaderException("Odd number of bytes in an UTF-16 stream"));
|
||||
break;
|
||||
case 3, 4:
|
||||
enforce(stream_.available % 4 == 0,
|
||||
new ReaderException("Number of bytes in an UTF-32 stream not divisible by 4"));
|
||||
utf_ = UTF._32;
|
||||
break;
|
||||
default: assert(false, "Unknown UTF BOM");
|
||||
}
|
||||
}
|
||||
|
||||
///Destroy the Reader.
|
||||
~this()
|
||||
{
|
||||
clear(buffer_);
|
||||
buffer_ = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get character at specified index relative to current position.
|
||||
*
|
||||
* Params: index = Index of the character to get relative to current position
|
||||
* in the stream.
|
||||
*
|
||||
* Returns: Character at specified position.
|
||||
*
|
||||
* Throws: ReaderException if trying to read past the end of the stream
|
||||
* or if invalid data is read.
|
||||
*/
|
||||
dchar peek(in size_t index = 0)
|
||||
{
|
||||
updateBuffer(index + 1);
|
||||
|
||||
enforce(buffer_.length >= bufferOffset_ + index + 1,
|
||||
new ReaderException("Trying to read past the end of the stream"));
|
||||
return buffer_[bufferOffset_ + index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get specified number of characters starting at current position.
|
||||
*
|
||||
* Params: length = Number of characters to get.
|
||||
*
|
||||
* Returns: Characters starting at current position.
|
||||
*
|
||||
* Throws: ReaderException if trying to read past the end of the stream
|
||||
* or if invalid data is read.
|
||||
*/
|
||||
dstring prefix(in size_t length)
|
||||
{
|
||||
if(length == 0){return "";}
|
||||
updateBuffer(length);
|
||||
const end = min(buffer_.length, bufferOffset_ + length);
|
||||
//need to duplicate as we change buffer content with C functions
|
||||
//and could end up with returned string referencing changed data
|
||||
return cast(dstring)buffer_[bufferOffset_ .. end].dup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next character, moving stream position beyond it.
|
||||
*
|
||||
* Returns: Next character.
|
||||
*
|
||||
* Throws: ReaderException if trying to read past the end of the stream
|
||||
* or if invalid data is read.
|
||||
*/
|
||||
dchar get()
|
||||
{
|
||||
const result = peek();
|
||||
forward();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get specified number of characters, moving stream position beyond them.
|
||||
*
|
||||
* Params: length = Number or characters to get.
|
||||
*
|
||||
* Returns: Characters starting at current position.
|
||||
*
|
||||
* Throws: ReaderException if trying to read past the end of the stream
|
||||
* or if invalid data is read.
|
||||
*/
|
||||
dstring get(in size_t length)
|
||||
{
|
||||
dstring result = prefix(length);
|
||||
forward(length);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move current position forward.
|
||||
*
|
||||
* Params: length = Number of characters to move position forward.
|
||||
*
|
||||
* Throws: ReaderException if trying to read past the end of the stream
|
||||
* or if invalid data is read.
|
||||
*/
|
||||
void forward(size_t length = 1)
|
||||
{
|
||||
updateBuffer(length + 1);
|
||||
|
||||
while(length > 0)
|
||||
{
|
||||
const c = buffer_[bufferOffset_];
|
||||
++bufferOffset_;
|
||||
++charIndex_;
|
||||
//new line
|
||||
if(['\n', '\x85', '\u2028', '\u2029'].canFind(c) ||
|
||||
(c == '\r' && buffer_[bufferOffset_] != '\n'))
|
||||
{
|
||||
++line_;
|
||||
column_ = 0;
|
||||
}
|
||||
else if(c != '\uFEFF'){++column_;}
|
||||
--length;
|
||||
}
|
||||
}
|
||||
|
||||
///Get a string describing current stream position, used for error messages.
|
||||
@property Mark mark() const {return Mark(line_, column_);}
|
||||
|
||||
///Get current line number.
|
||||
@property uint line() const {return line_;}
|
||||
|
||||
///Get current line number.
|
||||
@property uint column() const {return column_;}
|
||||
|
||||
///Get index of the current character in the stream.
|
||||
@property size_t charIndex() const {return charIndex_;}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Update buffer to be able to read length characters after buffer offset.
|
||||
*
|
||||
* If there are not enough characters in the stream, it will get
|
||||
* as many as possible.
|
||||
*
|
||||
* Params: length = Number of characters we need to read.
|
||||
*
|
||||
* Throws: ReaderException if trying to read past the end of the stream
|
||||
* or if invalid data is read.
|
||||
*/
|
||||
void updateBuffer(in size_t length)
|
||||
{
|
||||
if(buffer_.length > bufferOffset_ + length){return;}
|
||||
|
||||
//get rid of unneeded data in the buffer
|
||||
if(bufferOffset_ > 0)
|
||||
{
|
||||
size_t bufferLength = buffer_.length - bufferOffset_;
|
||||
memmove(buffer_.ptr, buffer_.ptr + bufferOffset_,
|
||||
bufferLength * dchar.sizeof);
|
||||
buffer_.length = bufferLength;
|
||||
bufferOffset_ = 0;
|
||||
}
|
||||
|
||||
////load chars in batches of at most 64 bytes
|
||||
while(buffer_.length <= bufferOffset_ + length)
|
||||
{
|
||||
loadChars(16);
|
||||
|
||||
if(done)
|
||||
{
|
||||
if(buffer_.length == 0 || buffer_[$ - 1] != '\0')
|
||||
{
|
||||
buffer_ ~= '\0';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load at most specified number of characters.
|
||||
*
|
||||
* Params: chars = Maximum number of characters to load.
|
||||
*
|
||||
* Throws: ReaderException on unicode decoding error,
|
||||
* if nonprintable characters are detected, or
|
||||
* if there is an error reading from the stream.
|
||||
*/
|
||||
void loadChars(in uint chars)
|
||||
{
|
||||
const oldLength = buffer_.length;
|
||||
|
||||
/**
|
||||
* Get next character from the stream.
|
||||
*
|
||||
* Params: available = Bytes available in the stream.
|
||||
*
|
||||
* Returns: Next character in the stream.
|
||||
*/
|
||||
dchar getDChar(in size_t available)
|
||||
{
|
||||
switch(utf_)
|
||||
{
|
||||
case UTF._8:
|
||||
//Temp buffer for moving data in rawBuffer8_.
|
||||
char[bufferLength8_] temp;
|
||||
//Shortcut for ASCII.
|
||||
if(rawUsed_ > 0 && rawBuffer8_[0] < 128)
|
||||
{
|
||||
//Get the first byte (one char in ASCII).
|
||||
const dchar result = rawBuffer8_[0];
|
||||
--rawUsed_;
|
||||
//Move the data.
|
||||
temp[0 .. rawUsed_] = rawBuffer8_[1 .. rawUsed_ + 1];
|
||||
rawBuffer8_[0 .. rawUsed_] = temp[0 .. rawUsed_];
|
||||
return result;
|
||||
}
|
||||
|
||||
//Bytes to read.
|
||||
const readBytes = min(available, bufferLength8_ - rawUsed_);
|
||||
//Length of data in rawBuffer8_ after reading.
|
||||
const len = rawUsed_ + readBytes;
|
||||
//Read the data.
|
||||
stream_.readExact(rawBuffer8_.ptr + rawUsed_, readBytes);
|
||||
|
||||
//After decoding, this will point to the first byte not decoded.
|
||||
size_t idx = 0;
|
||||
const dchar result = decode(rawBuffer8_, idx);
|
||||
rawUsed_ = cast(uint)(len - idx);
|
||||
|
||||
//Move the data.
|
||||
temp[0 .. rawUsed_] = rawBuffer8_[idx .. len];
|
||||
rawBuffer8_[0 .. rawUsed_] = temp[0 .. rawUsed_];
|
||||
return result;
|
||||
case UTF._16:
|
||||
//Temp buffer for moving data in rawBuffer8_.
|
||||
wchar[bufferLength16_] temp;
|
||||
//Words to read.
|
||||
size_t readWords = min(available / 2, bufferLength16_ - rawUsed_);
|
||||
//Length of data in rawBuffer16_ after reading.
|
||||
size_t len = rawUsed_;
|
||||
//Read the data.
|
||||
while(readWords > 0)
|
||||
{
|
||||
//Due to a bug in std.stream, we have to use getcw here.
|
||||
rawBuffer16_[len] = stream_.getcw();
|
||||
--readWords;
|
||||
++len;
|
||||
}
|
||||
|
||||
//After decoding, this will point to the first word not decoded.
|
||||
size_t idx = 0;
|
||||
const dchar result = decode(rawBuffer16_, idx);
|
||||
rawUsed_ = cast(uint)(len - idx);
|
||||
|
||||
//Move the data.
|
||||
temp[0 .. rawUsed_] = rawBuffer16_[idx .. len];
|
||||
rawBuffer16_[0 .. rawUsed_] = temp[0 .. rawUsed_];
|
||||
return result;
|
||||
case UTF._32:
|
||||
dchar result;
|
||||
stream_.read(result);
|
||||
return result;
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
const oldPosition = stream_.position;
|
||||
try
|
||||
{
|
||||
foreach(i; 0 .. chars)
|
||||
{
|
||||
if(done){break;}
|
||||
const available = stream_.available;
|
||||
buffer_ ~= getDChar(available);
|
||||
}
|
||||
}
|
||||
catch(UtfException e)
|
||||
{
|
||||
const position = stream_.position;
|
||||
throw new ReaderException("Unicode decoding error between bytes " ~
|
||||
to!string(oldPosition) ~ " and " ~
|
||||
to!string(position) ~ " " ~ e.msg);
|
||||
}
|
||||
catch(ReadException e)
|
||||
{
|
||||
throw new ReaderException("Error reading from the stream: " ~ e.msg);
|
||||
}
|
||||
|
||||
enforce(printable(buffer_[oldLength .. $]),
|
||||
new ReaderException("Special unicode characters are not allowed"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if all characters in an array are printable.
|
||||
*
|
||||
* Params: chars = Characters to check.
|
||||
*
|
||||
* Returns: True if all the characters are printable, false otherwise.
|
||||
*/
|
||||
static pure bool printable(const ref dchar[] chars)
|
||||
{
|
||||
foreach(c; chars)
|
||||
{
|
||||
if(!((c == 0x09 || c == 0x0A || c == 0x0D || c == 0x85) ||
|
||||
(c >= 0x20 && c <= 0x7E) ||
|
||||
(c >= 0xA0 && c <= '\uD7FF') ||
|
||||
(c >= '\uE000' && c <= '\uFFFD')))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
///Are we done reading?
|
||||
@property bool done()
|
||||
{
|
||||
return (stream_.available == 0 &&
|
||||
((utf_ == UTF._8 && rawUsed_ == 0) ||
|
||||
(utf_ == UTF._16 && rawUsed_ == 0) ||
|
||||
utf_ == UTF._32));
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
writeln("D:YAML reader endian unittest");
|
||||
void endian_test(ubyte[] data, UTF utf_expected, Endian endian_expected)
|
||||
{
|
||||
auto reader = new Reader(new MemoryStream(data));
|
||||
assert(reader.utf_ == utf_expected);
|
||||
assert(reader.stream_.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, UTF._16, Endian.LittleEndian);
|
||||
endian_test(big_endian_utf_16, UTF._16, Endian.BigEndian);
|
||||
}
|
||||
unittest
|
||||
{
|
||||
writeln("D:YAML reader peek/prefix/forward unittest");
|
||||
ubyte[] data = ByteOrderMarks[BOM.UTF8] ~ cast(ubyte[])"data";
|
||||
auto reader = new Reader(new MemoryStream(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)));
|
||||
}
|
||||
unittest
|
||||
{
|
||||
writeln("D:YAML reader UTF formats unittest");
|
||||
dchar[] data = cast(dchar[])"data";
|
||||
void utf_test(T)(T[] data, BOM bom)
|
||||
{
|
||||
ubyte[] bytes = ByteOrderMarks[bom] ~
|
||||
(cast(ubyte*)data.ptr)[0 .. data.length * T.sizeof];
|
||||
auto reader = new Reader(new MemoryStream(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);
|
||||
}
|
||||
}
|
221
dyaml/resolver.d
Normal file
|
@ -0,0 +1,221 @@
|
|||
|
||||
// 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.stdio;
|
||||
import std.typecons;
|
||||
import std.utf;
|
||||
|
||||
import dyaml.node;
|
||||
import dyaml.exception;
|
||||
|
||||
|
||||
/**
|
||||
* Resolves YAML tags (data types).
|
||||
*
|
||||
* Can be used to implicitly resolve custom data types of scalar values.
|
||||
*/
|
||||
final class Resolver
|
||||
{
|
||||
private:
|
||||
///Default tag to use for scalars.
|
||||
static string defaultScalarTag_ = "tag:yaml.org,2002:str";
|
||||
///Default tag to use for sequences.
|
||||
static string defaultSequenceTag_ = "tag:yaml.org,2002:seq";
|
||||
///Default tag to use for mappings.
|
||||
static 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, Regex!char)[][dchar] yamlImplicitResolvers_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a Resolver.
|
||||
*
|
||||
* If you don't want to implicitly resolve default YAML tags/data types,
|
||||
* you can use defaultImplicitResolvers to disable default resolvers.
|
||||
*
|
||||
* Params: defaultImplicitResolvers = Use default YAML implicit resolvers?
|
||||
*/
|
||||
this(in bool defaultImplicitResolvers = true)
|
||||
{
|
||||
if(defaultImplicitResolvers){addImplicitResolvers();}
|
||||
}
|
||||
|
||||
///Destroy the Resolver.
|
||||
~this()
|
||||
{
|
||||
clear(yamlImplicitResolvers_);
|
||||
yamlImplicitResolvers_ = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an implicit scalar resolver.
|
||||
*
|
||||
* If a scalar matches regexp and starts with one of the characters in first,
|
||||
* its _tag is set to tag. If the scalar matches more than one resolver
|
||||
* regular expression, resolvers added _first override those added later.
|
||||
* Default resolvers override any user specified resolvers.
|
||||
*
|
||||
* 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, Regex!char regexp, in string first)
|
||||
{
|
||||
foreach(const dchar c; first)
|
||||
{
|
||||
if((c in yamlImplicitResolvers_) is null)
|
||||
{
|
||||
yamlImplicitResolvers_[c] = [];
|
||||
}
|
||||
yamlImplicitResolvers_[c] ~= tuple(tag, regexp);
|
||||
}
|
||||
}
|
||||
|
||||
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(NodeID kind, string tag, string value, in bool implicit)
|
||||
{
|
||||
if(tag !is null && tag != "!"){return tag;}
|
||||
|
||||
if(kind == NodeID.Scalar)
|
||||
{
|
||||
if(implicit)
|
||||
{
|
||||
//Get the first char of the value.
|
||||
size_t dummy;
|
||||
const dchar first = value.length == 0 ? '\0' : decode(value, dummy);
|
||||
|
||||
auto resolvers = (first in yamlImplicitResolvers_) is null ?
|
||||
[] : yamlImplicitResolvers_[first];
|
||||
|
||||
foreach(resolver; resolvers)
|
||||
{
|
||||
tag = resolver[0];
|
||||
auto regexp = resolver[1];
|
||||
if(!(match(value, regexp).empty)){return tag;}
|
||||
}
|
||||
}
|
||||
return defaultScalarTag_;
|
||||
}
|
||||
else if(kind == NodeID.Sequence){return defaultSequenceTag_;}
|
||||
else if(kind == NodeID.Mapping) {return defaultMappingTag_;}
|
||||
assert(false, "This line of code should never be reached");
|
||||
}
|
||||
unittest
|
||||
{
|
||||
writeln("D:YAML Resolver unittest");
|
||||
|
||||
auto resolver = new Resolver();
|
||||
|
||||
bool tagMatch(string tag, string[] values)
|
||||
{
|
||||
foreach(value; values)
|
||||
{
|
||||
if(tag != resolver.resolve(NodeID.Scalar, null, value, true))
|
||||
{
|
||||
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", ["!", "&", "*"]));
|
||||
}
|
||||
|
||||
private:
|
||||
///Add default implicit resolvers.
|
||||
void addImplicitResolvers()
|
||||
{
|
||||
addImplicitResolver("tag:yaml.org,2002:bool",
|
||||
regex(r"^(?:yes|Yes|YES|no|No|NO|true|True|TRUE"
|
||||
"|false|False|FALSE|on|On|ON|off|Off|OFF)$"),
|
||||
"yYnNtTfFoO");
|
||||
addImplicitResolver("tag:yaml.org,2002:float",
|
||||
regex(r"^(?:[-+]?([0-9][0-9_]*)\\.[0-9_]*"
|
||||
"(?:[eE][-+][0-9]+)?|[-+]?(?:[0-9][0-9_]"
|
||||
"*)?\\.[0-9_]+(?:[eE][-+][0-9]+)?|[-+]?"
|
||||
"[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]"
|
||||
"*|[-+]?\\.(?:inf|Inf|INF)|\\."
|
||||
"(?:nan|NaN|NAN))$"),
|
||||
"-+0123456789.");
|
||||
addImplicitResolver("tag:yaml.org,2002:int",
|
||||
regex(r"^(?:[-+]?0b[0-1_]+"
|
||||
"|[-+]?0[0-7_]+"
|
||||
"|[-+]?(?:0|[1-9][0-9_]*)"
|
||||
"|[-+]?0x[0-9a-fA-F_]+"
|
||||
"|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$"),
|
||||
"-+0123456789");
|
||||
addImplicitResolver("tag:yaml.org,2002:merge", regex(r"^<<$"), "<");
|
||||
|
||||
addImplicitResolver("tag:yaml.org,2002:null",
|
||||
regex(r"^(?:~|null|Null|NULL|\0)?$"), "~nN\0");
|
||||
addImplicitResolver("tag:yaml.org,2002:timestamp",
|
||||
regex(r"^[0-9][0-9][0-9][0-9]-[0-9][0-9]-"
|
||||
"[0-9][0-9]|[0-9][0-9][0-9][0-9]-[0-9]"
|
||||
"[0-9]?-[0-9][0-9]?[Tt]|[ \t]+[0-9]"
|
||||
"[0-9]?:[0-9][0-9]:[0-9][0-9]"
|
||||
"(?:\\.[0-9]*)?(?:[ \t]*Z|[-+][0-9]"
|
||||
"[0-9]?(?::[0-9][0-9])?)?$"), "0123456789");
|
||||
addImplicitResolver("tag:yaml.org,2002:value", regex(r"^=$"), "=");
|
||||
|
||||
|
||||
//The following resolver is only for documentation purposes. It cannot work
|
||||
//because plain scalars cannot start with '!', '&', or '*'.
|
||||
addImplicitResolver("tag:yaml.org,2002:yaml", regex(r"^(?:!|&|\*)$"), "!&*");
|
||||
}
|
||||
}
|
1632
dyaml/scanner.d
Normal file
139
dyaml/token.d
Normal file
|
@ -0,0 +1,139 @@
|
|||
|
||||
// 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 tokens.
|
||||
* Code based on PyYAML: http://www.pyyaml.org
|
||||
*/
|
||||
module dyaml.token;
|
||||
|
||||
|
||||
import dyaml.exception;
|
||||
import dyaml.reader;
|
||||
|
||||
|
||||
package:
|
||||
///Token types.
|
||||
enum TokenID : ubyte
|
||||
{
|
||||
Invalid = 0, /// Invalid (uninitialized) token
|
||||
Directive, /// DIRECTIVE
|
||||
DocumentStart, /// DOCUMENT-START
|
||||
DocumentEnd, /// DOCUMENT-END
|
||||
StreamStart, /// STREAM-START
|
||||
StreamEnd, /// STREAM-END
|
||||
BlockSequenceStart, /// BLOCK-SEQUENCE-START
|
||||
BlockMappingStart, /// BLOCK-MAPPING-START
|
||||
BlockEnd, /// BLOCK-END
|
||||
FlowSequenceStart, /// FLOW-SEQUENCE-START
|
||||
FlowMappingStart, /// FLOW-MAPPING-START
|
||||
FlowSequenceEnd, /// FLOW-SEQUENCE-END
|
||||
FlowMappingEnd, /// FLOW-MAPPING-END
|
||||
Key, /// KEY
|
||||
Value, /// VALUE
|
||||
BlockEntry, /// BLOCK-ENTRY
|
||||
FlowEntry, /// FLOW-ENTRY
|
||||
Alias, /// ALIAS
|
||||
Anchor, /// ANCHOR
|
||||
Tag, /// TAG
|
||||
Scalar /// SCALAR
|
||||
}
|
||||
|
||||
///Scalar styles.
|
||||
enum ScalarStyle : ubyte
|
||||
{
|
||||
Invalid = 0, /// Invalid (uninitialized) style
|
||||
Literal, /// | (Literal block style)
|
||||
Folded, /// > (Folded block style)
|
||||
Plain, /// Plain scalar
|
||||
SingleQuoted, /// Single quoted scalar
|
||||
DoubleQuoted /// Double quoted scalar
|
||||
}
|
||||
|
||||
/**
|
||||
* Token produced by scanner.
|
||||
*
|
||||
* 32 bytes on 64-bit.
|
||||
*/
|
||||
immutable struct Token
|
||||
{
|
||||
///Value of the token, if any.
|
||||
string value;
|
||||
///Start position of the token in file/stream.
|
||||
Mark startMark;
|
||||
///End position of the token in file/stream.
|
||||
Mark endMark;
|
||||
///Token type.
|
||||
TokenID id;
|
||||
///Style of scalar token, if this is a scalar token.
|
||||
ScalarStyle style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a directive token.
|
||||
*
|
||||
* Params: start = Start position of the token.
|
||||
* end = End position of the token.
|
||||
* value = Value of the token.
|
||||
*/
|
||||
Token directiveToken(in Mark start, in Mark end, in string value) pure
|
||||
{
|
||||
return Token(value, start, end, TokenID.Directive);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)(in Mark start, in Mark end) pure
|
||||
{
|
||||
return Token(null, start, end, id);
|
||||
}
|
||||
|
||||
///Aliases for construction of simple token types.
|
||||
alias simpleToken!(TokenID.StreamStart) streamStartToken;
|
||||
alias simpleToken!(TokenID.StreamEnd) streamEndToken;
|
||||
alias simpleToken!(TokenID.BlockSequenceStart) blockSequenceStartToken;
|
||||
alias simpleToken!(TokenID.BlockMappingStart) blockMappingStartToken;
|
||||
alias simpleToken!(TokenID.BlockEnd) blockEndToken;
|
||||
alias simpleToken!(TokenID.Key) keyToken;
|
||||
alias simpleToken!(TokenID.Value) valueToken;
|
||||
alias simpleToken!(TokenID.BlockEntry) blockEntryToken;
|
||||
alias simpleToken!(TokenID.FlowEntry) flowEntryToken;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
Token simpleValueToken(TokenID id)(in Mark start, in Mark end, string value) pure
|
||||
{
|
||||
return Token(value, start, end, id);
|
||||
}
|
||||
|
||||
///Alias for construction of tag token.
|
||||
alias simpleValueToken!(TokenID.Tag) tagToken;
|
||||
alias simpleValueToken!(TokenID.Alias) aliasToken;
|
||||
alias simpleValueToken!(TokenID.Anchor) anchorToken;
|
||||
|
||||
/**
|
||||
* 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(in Mark start, in Mark end, in string value, in ScalarStyle style) pure
|
||||
{
|
||||
return Token(value, start, end, TokenID.Scalar, style);
|
||||
}
|
36
dyaml/util.d
Normal file
|
@ -0,0 +1,36 @@
|
|||
|
||||
// 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.util;
|
||||
|
||||
package:
|
||||
|
||||
|
||||
///Is given character YAML whitespace (space or tab)?
|
||||
bool isSpace(in dchar c){return c == ' ' || c == '\t';}
|
||||
|
||||
///Is given character YAML line break?
|
||||
bool isBreak(in dchar c)
|
||||
{
|
||||
return c == '\n' || c == '\r' || c == '\x85' || c == '\u2028' || c == '\u2029';
|
||||
}
|
||||
|
||||
///Is c the checked character?
|
||||
bool isChar(dchar checked)(in dchar c){return checked == c;}
|
||||
|
||||
///Function that or's specified functions with a character input.
|
||||
bool or(F ...)(in dchar input)
|
||||
{
|
||||
foreach(f; F)
|
||||
{
|
||||
if(f(input)){return true;}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
///Convenience aliases.
|
||||
alias isChar!'\0' isZero;
|
||||
alias or!(isZero, isBreak) isBreakOrZero;
|
2
examples/constructor/Makefile
Normal file
|
@ -0,0 +1,2 @@
|
|||
main:
|
||||
dmd -w -I../../ -L-L../../ -L-ldyaml main.d
|
8
examples/constructor/input.yaml
Normal file
|
@ -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
|
110
examples/constructor/main.d
Normal file
|
@ -0,0 +1,110 @@
|
|||
import std.ascii;
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
import yaml;
|
||||
|
||||
struct Color
|
||||
{
|
||||
ubyte red;
|
||||
ubyte green;
|
||||
ubyte blue;
|
||||
}
|
||||
|
||||
Color constructColorScalar(Mark start, Mark end, string value)
|
||||
{
|
||||
if(value.length != 6)
|
||||
{
|
||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
||||
}
|
||||
//We don't need to check for uppercase chars this way.
|
||||
value = value.toLower();
|
||||
|
||||
//Get value of a hex digit.
|
||||
uint hex(char c)
|
||||
{
|
||||
if(!std.ascii.isHexDigit(c))
|
||||
{
|
||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
||||
}
|
||||
|
||||
if(std.ascii.isDigit(c))
|
||||
{
|
||||
return c - '0';
|
||||
}
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
|
||||
Color result;
|
||||
result.red = cast(ubyte)(16 * hex(value[0]) + hex(value[1]));
|
||||
result.green = cast(ubyte)(16 * hex(value[2]) + hex(value[3]));
|
||||
result.blue = cast(ubyte)(16 * hex(value[4]) + hex(value[5]));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Color constructColorMapping(Mark start, Mark end, Node.Pair[] pairs)
|
||||
{
|
||||
int r, g, b;
|
||||
r = g = b = -1;
|
||||
bool error = pairs.length != 3;
|
||||
|
||||
foreach(ref pair; pairs)
|
||||
{
|
||||
//Key might not be a string, and value might not be an int,
|
||||
//so we need to check for that
|
||||
try
|
||||
{
|
||||
switch(pair.key.get!string)
|
||||
{
|
||||
case "r": r = pair.value.get!int; break;
|
||||
case "g": g = pair.value.get!int; break;
|
||||
case "b": b = pair.value.get!int; break;
|
||||
default: error = true;
|
||||
}
|
||||
}
|
||||
catch(NodeException e)
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
|
||||
{
|
||||
throw new ConstructorException("Invalid color", start, end);
|
||||
}
|
||||
|
||||
return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
auto red = Color(255, 0, 0);
|
||||
auto orange = Color(255, 255, 0);
|
||||
|
||||
try
|
||||
{
|
||||
auto constructor = new Constructor;
|
||||
//both functions handle the same tag, but one handles scalar, one mapping.
|
||||
constructor.addConstructor("!color", &constructColorScalar);
|
||||
constructor.addConstructor("!color-mapping", &constructColorMapping);
|
||||
|
||||
auto loader = new Loader("input.yaml", constructor, new Resolver);
|
||||
|
||||
auto root = loader.loadSingleDocument();
|
||||
|
||||
if(root["scalar-red"].get!Color == red &&
|
||||
root["mapping-red"].get!Color == red &&
|
||||
root["scalar-orange"].get!Color == orange &&
|
||||
root["mapping-orange"].get!Color == orange)
|
||||
{
|
||||
writeln("SUCCESS");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch(YAMLException e)
|
||||
{
|
||||
writeln(e.msg);
|
||||
}
|
||||
|
||||
writeln("FAILURE");
|
||||
}
|
2
examples/getting_started/Makefile
Normal file
|
@ -0,0 +1,2 @@
|
|||
main:
|
||||
dmd -w -I../../ -L-L../../ -L-ldyaml main.d
|
4
examples/getting_started/input.yaml
Normal file
|
@ -0,0 +1,4 @@
|
|||
Hello World :
|
||||
- Hello
|
||||
- World
|
||||
Answer : 42
|
12
examples/getting_started/main.d
Normal file
|
@ -0,0 +1,12 @@
|
|||
import std.stdio;
|
||||
import yaml;
|
||||
|
||||
void main()
|
||||
{
|
||||
yaml.Node root = yaml.load("input.yaml");
|
||||
foreach(string word; root["Hello World"])
|
||||
{
|
||||
writeln(word);
|
||||
}
|
||||
writeln("The answer is ", root["Answer"].get!int);
|
||||
}
|
2
examples/resolver/Makefile
Normal file
|
@ -0,0 +1,2 @@
|
|||
main:
|
||||
dmd -w -I../../ -L-L../../ -L-ldyaml main.d
|
8
examples/resolver/input.yaml
Normal file
|
@ -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
|
114
examples/resolver/main.d
Normal file
|
@ -0,0 +1,114 @@
|
|||
import std.ascii;
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
import yaml;
|
||||
|
||||
struct Color
|
||||
{
|
||||
ubyte red;
|
||||
ubyte green;
|
||||
ubyte blue;
|
||||
}
|
||||
|
||||
Color constructColorScalar(Mark start, Mark end, string value)
|
||||
{
|
||||
if(value.length != 6)
|
||||
{
|
||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
||||
}
|
||||
//We don't need to check for uppercase chars this way.
|
||||
value = value.toLower();
|
||||
|
||||
//Get value of a hex digit.
|
||||
uint hex(char c)
|
||||
{
|
||||
if(!std.ascii.isHexDigit(c))
|
||||
{
|
||||
throw new ConstructorException("Invalid color: " ~ value, start, end);
|
||||
}
|
||||
|
||||
if(std.ascii.isDigit(c))
|
||||
{
|
||||
return c - '0';
|
||||
}
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
|
||||
Color result;
|
||||
result.red = cast(ubyte)(16 * hex(value[0]) + hex(value[1]));
|
||||
result.green = cast(ubyte)(16 * hex(value[2]) + hex(value[3]));
|
||||
result.blue = cast(ubyte)(16 * hex(value[4]) + hex(value[5]));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Color constructColorMapping(Mark start, Mark end, Node.Pair[] pairs)
|
||||
{
|
||||
int r, g, b;
|
||||
r = g = b = -1;
|
||||
bool error = pairs.length != 3;
|
||||
|
||||
foreach(ref pair; pairs)
|
||||
{
|
||||
//Key might not be a string, and value might not be an int,
|
||||
//so we need to check for that
|
||||
try
|
||||
{
|
||||
switch(pair.key.get!string)
|
||||
{
|
||||
case "r": r = pair.value.get!int; break;
|
||||
case "g": g = pair.value.get!int; break;
|
||||
case "b": b = pair.value.get!int; break;
|
||||
default: error = true;
|
||||
}
|
||||
}
|
||||
catch(NodeException e)
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
|
||||
{
|
||||
throw new ConstructorException("Invalid color", start, end);
|
||||
}
|
||||
|
||||
return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
auto red = Color(255, 0, 0);
|
||||
auto orange = Color(255, 255, 0);
|
||||
|
||||
try
|
||||
{
|
||||
auto constructor = new Constructor;
|
||||
//both functions handle the same tag, but one handles scalar, one mapping.
|
||||
constructor.addConstructor("!color", &constructColorScalar);
|
||||
constructor.addConstructor("!color-mapping", &constructColorMapping);
|
||||
|
||||
auto resolver = new Resolver;
|
||||
resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"),
|
||||
"0123456789abcdefABCDEF");
|
||||
|
||||
auto loader = new Loader("input.yaml", constructor, resolver);
|
||||
|
||||
auto root = loader.loadSingleDocument();
|
||||
|
||||
if(root["scalar-red"].get!Color == red &&
|
||||
root["mapping-red"].get!Color == red &&
|
||||
root["scalar-orange"].get!Color == orange &&
|
||||
root["mapping-orange"].get!Color == orange)
|
||||
{
|
||||
writeln("SUCCESS");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch(YAMLException e)
|
||||
{
|
||||
writeln(e.msg);
|
||||
}
|
||||
|
||||
writeln("FAILURE");
|
||||
}
|
1
test/data/a-nasty-libyaml-bug.loader-error
Normal file
|
@ -0,0 +1 @@
|
|||
[ [
|
1
test/data/aliases-cdumper-bug.code
Normal file
|
@ -0,0 +1 @@
|
|||
#dummy used in constructor test
|
8
test/data/aliases.events
Normal file
|
@ -0,0 +1,8 @@
|
|||
- !StreamStart
|
||||
- !DocumentStart
|
||||
- !SequenceStart
|
||||
- !Scalar { anchor: 'myanchor', tag: '!mytag', value: 'data' }
|
||||
- !Alias { anchor: 'myanchor' }
|
||||
- !SequenceEnd
|
||||
- !DocumentEnd
|
||||
- !StreamEnd
|
4
test/data/bool.data
Normal file
|
@ -0,0 +1,4 @@
|
|||
- yes
|
||||
- NO
|
||||
- True
|
||||
- on
|
1
test/data/bool.detect
Normal file
|
@ -0,0 +1 @@
|
|||
tag:yaml.org,2002:bool
|
1
test/data/colon-in-flow-context.loader-error
Normal file
|
@ -0,0 +1 @@
|
|||
{ foo:bar }
|
1
test/data/construct-binary.code
Normal file
|
@ -0,0 +1 @@
|
|||
#dummy used in constructor test
|
12
test/data/construct-binary.data
Normal file
|
@ -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.
|
1
test/data/construct-bool.code
Normal file
|
@ -0,0 +1 @@
|
|||
#dummy used in constructor test
|
9
test/data/construct-bool.data
Normal file
|
@ -0,0 +1,9 @@
|
|||
canonical: yes
|
||||
answer: NO
|
||||
logical: True
|
||||
option: on
|
||||
|
||||
|
||||
but:
|
||||
y: is a string
|
||||
n: is a string
|
1
test/data/construct-custom.code
Normal file
|
@ -0,0 +1 @@
|
|||
#dummy used in constructor test
|
9
test/data/construct-custom.data
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
- !tag1
|
||||
x: 1
|
||||
- !tag1
|
||||
x: 1
|
||||
'y': 2
|
||||
z: 3
|
||||
- !tag2
|
||||
10
|
1
test/data/construct-float.code
Normal file
|
@ -0,0 +1 @@
|
|||
#dummy used in constructor test
|
6
test/data/construct-float.data
Normal file
|
@ -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
|
1
test/data/construct-int.code
Normal file
|
@ -0,0 +1 @@
|
|||
#dummy used in constructor test
|
6
test/data/construct-int.data
Normal file
|
@ -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
|
1
test/data/construct-map.code
Normal file
|
@ -0,0 +1 @@
|
|||
#dummy used in constructor test
|
6
test/data/construct-map.data
Normal file
|
@ -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 }
|
1
test/data/construct-merge.code
Normal file
|
@ -0,0 +1 @@
|
|||
#dummy used in constructor test
|
27
test/data/construct-merge.data
Normal file
|
@ -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
|
1
test/data/construct-null.code
Normal file
|
@ -0,0 +1 @@
|
|||
#dummy used in constructor test
|
18
test/data/construct-null.data
Normal file
|
@ -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
|