forked from lix-project/lix
Merge remote-tracking branch 'origin/master' into flakes
This commit is contained in:
commit
6636808e90
|
@ -14,7 +14,8 @@
|
||||||
<varlistentry><term><envar>IN_NIX_SHELL</envar></term>
|
<varlistentry><term><envar>IN_NIX_SHELL</envar></term>
|
||||||
|
|
||||||
<listitem><para>Indicator that tells if the current environment was set up by
|
<listitem><para>Indicator that tells if the current environment was set up by
|
||||||
<command>nix-shell</command>.</para></listitem>
|
<command>nix-shell</command>. Since Nix 2.0 the values are
|
||||||
|
<literal>"pure"</literal> and <literal>"impure"</literal></para></listitem>
|
||||||
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|
|
@ -217,7 +217,25 @@ but can also be written as:
|
||||||
ellipsis(<literal>...</literal>) as you can access attribute names as
|
ellipsis(<literal>...</literal>) as you can access attribute names as
|
||||||
<literal>a</literal>, using <literal>args.a</literal>, which was given as an
|
<literal>a</literal>, using <literal>args.a</literal>, which was given as an
|
||||||
additional attribute to the function.
|
additional attribute to the function.
|
||||||
</para></listitem>
|
</para>
|
||||||
|
|
||||||
|
<warning>
|
||||||
|
<para>
|
||||||
|
The <literal>args@</literal> expression is bound to the argument passed to the function which
|
||||||
|
means that attributes with defaults that aren't explicitly specified in the function call
|
||||||
|
won't cause an evaluation error, but won't exist in <literal>args</literal>.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
For instance
|
||||||
|
<programlisting>
|
||||||
|
let
|
||||||
|
function = args@{ a ? 23, ... }: args;
|
||||||
|
in
|
||||||
|
function {}
|
||||||
|
</programlisting>
|
||||||
|
will evaluate to an empty attribute set.
|
||||||
|
</para>
|
||||||
|
</warning></listitem>
|
||||||
|
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,6 @@
|
||||||
if [ -n "${__ETC_PROFILE_NIX_SOURCED:-}" ]; then return; fi
|
if [ -n "${__ETC_PROFILE_NIX_SOURCED:-}" ]; then return; fi
|
||||||
__ETC_PROFILE_NIX_SOURCED=1
|
__ETC_PROFILE_NIX_SOURCED=1
|
||||||
|
|
||||||
# Set up secure multi-user builds: non-root users build through the
|
|
||||||
# Nix daemon.
|
|
||||||
if [ "$USER" != root -o ! -w @localstatedir@/nix/db ]; then
|
|
||||||
export NIX_REMOTE=daemon
|
|
||||||
fi
|
|
||||||
|
|
||||||
export NIX_USER_PROFILE_DIR="@localstatedir@/nix/profiles/per-user/$USER"
|
export NIX_USER_PROFILE_DIR="@localstatedir@/nix/profiles/per-user/$USER"
|
||||||
export NIX_PROFILES="@localstatedir@/nix/profiles/default $HOME/.nix-profile"
|
export NIX_PROFILES="@localstatedir@/nix/profiles/default $HOME/.nix-profile"
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ if [ -n "$HOME" ] && [ -n "$USER" ]; then
|
||||||
|
|
||||||
# Set up environment.
|
# Set up environment.
|
||||||
# This part should be kept in sync with nixpkgs:nixos/modules/programs/environment.nix
|
# This part should be kept in sync with nixpkgs:nixos/modules/programs/environment.nix
|
||||||
NIX_PROFILES="@localstatedir@/nix/profiles/default $NIX_USER_PROFILE_DIR"
|
export NIX_PROFILES="@localstatedir@/nix/profiles/default $HOME/.nix-profile"
|
||||||
|
|
||||||
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
|
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
|
||||||
if [ -e /etc/ssl/certs/ca-certificates.crt ]; then # NixOS, Ubuntu, Debian, Gentoo, Arch
|
if [ -e /etc/ssl/certs/ca-certificates.crt ]; then # NixOS, Ubuntu, Debian, Gentoo, Arch
|
||||||
|
@ -79,5 +79,5 @@ if [ -n "$HOME" ] && [ -n "$USER" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export PATH="$NIX_LINK/bin:$__savedpath"
|
export PATH="$NIX_LINK/bin:$__savedpath"
|
||||||
unset __savedpath NIX_LINK NIX_USER_PROFILE_DIR NIX_PROFILES
|
unset __savedpath NIX_LINK NIX_USER_PROFILE_DIR
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
, nixpkgs ? builtins.fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/nixos-19.03.tar.gz
|
, nixpkgs ? builtins.fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/nixos-19.03.tar.gz
|
||||||
}:
|
}:
|
||||||
|
|
||||||
with import nixpkgs { system = builtins.currentSystem or "x86_64-linux"; };
|
with import (builtins.fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/nixos-19.03.tar.gz) { system = builtins.currentSystem or "x86_64-linux"; };
|
||||||
|
|
||||||
with import ./release-common.nix { inherit pkgs; };
|
with import ./release-common.nix { inherit pkgs; };
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
* @date May 2013
|
* @date May 2013
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _CPPTOML_H_
|
#ifndef CPPTOML_H
|
||||||
#define _CPPTOML_H_
|
#define CPPTOML_H
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
@ -84,11 +84,12 @@ class option
|
||||||
return &value_;
|
return &value_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const T& value_or(const T& alternative) const
|
template <class U>
|
||||||
|
T value_or(U&& alternative) const
|
||||||
{
|
{
|
||||||
if (!empty_)
|
if (!empty_)
|
||||||
return value_;
|
return value_;
|
||||||
return alternative;
|
return static_cast<T>(std::forward<U>(alternative));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -295,13 +296,12 @@ struct valid_value_or_string_convertible
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct value_traits<T, typename std::
|
struct value_traits<T, typename std::enable_if<
|
||||||
enable_if<valid_value_or_string_convertible<T>::
|
valid_value_or_string_convertible<T>::value>::type>
|
||||||
value>::type>
|
|
||||||
{
|
{
|
||||||
using value_type = typename std::
|
using value_type = typename std::conditional<
|
||||||
conditional<valid_value<typename std::decay<T>::type>::value,
|
valid_value<typename std::decay<T>::type>::value,
|
||||||
typename std::decay<T>::type, std::string>::type;
|
typename std::decay<T>::type, std::string>::type;
|
||||||
|
|
||||||
using type = value<value_type>;
|
using type = value<value_type>;
|
||||||
|
|
||||||
|
@ -312,12 +312,11 @@ struct value_traits<T, typename std::
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct value_traits<T,
|
struct value_traits<
|
||||||
typename std::
|
T,
|
||||||
enable_if<!valid_value_or_string_convertible<T>::value
|
typename std::enable_if<
|
||||||
&& std::is_floating_point<
|
!valid_value_or_string_convertible<T>::value
|
||||||
typename std::decay<T>::type>::value>::
|
&& std::is_floating_point<typename std::decay<T>::type>::value>::type>
|
||||||
type>
|
|
||||||
{
|
{
|
||||||
using value_type = typename std::decay<T>::type;
|
using value_type = typename std::decay<T>::type;
|
||||||
|
|
||||||
|
@ -330,11 +329,11 @@ struct value_traits<T,
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct value_traits<T,
|
struct value_traits<
|
||||||
typename std::
|
T, typename std::enable_if<
|
||||||
enable_if<!valid_value_or_string_convertible<T>::value
|
!valid_value_or_string_convertible<T>::value
|
||||||
&& std::is_signed<typename std::decay<T>::
|
&& !std::is_floating_point<typename std::decay<T>::type>::value
|
||||||
type>::value>::type>
|
&& std::is_signed<typename std::decay<T>::type>::value>::type>
|
||||||
{
|
{
|
||||||
using value_type = int64_t;
|
using value_type = int64_t;
|
||||||
|
|
||||||
|
@ -356,11 +355,10 @@ struct value_traits<T,
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct value_traits<T,
|
struct value_traits<
|
||||||
typename std::
|
T, typename std::enable_if<
|
||||||
enable_if<!valid_value_or_string_convertible<T>::value
|
!valid_value_or_string_convertible<T>::value
|
||||||
&& std::is_unsigned<typename std::decay<T>::
|
&& std::is_unsigned<typename std::decay<T>::type>::value>::type>
|
||||||
type>::value>::type>
|
|
||||||
{
|
{
|
||||||
using value_type = int64_t;
|
using value_type = int64_t;
|
||||||
|
|
||||||
|
@ -395,10 +393,15 @@ struct array_of_trait<array>
|
||||||
template <class T>
|
template <class T>
|
||||||
inline std::shared_ptr<typename value_traits<T>::type> make_value(T&& val);
|
inline std::shared_ptr<typename value_traits<T>::type> make_value(T&& val);
|
||||||
inline std::shared_ptr<array> make_array();
|
inline std::shared_ptr<array> make_array();
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
template <class T>
|
template <class T>
|
||||||
inline std::shared_ptr<T> make_element();
|
inline std::shared_ptr<T> make_element();
|
||||||
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<table> make_table();
|
inline std::shared_ptr<table> make_table();
|
||||||
inline std::shared_ptr<table_array> make_table_array();
|
inline std::shared_ptr<table_array> make_table_array(bool is_inline = false);
|
||||||
|
|
||||||
#if defined(CPPTOML_NO_RTTI)
|
#if defined(CPPTOML_NO_RTTI)
|
||||||
/// Base type used to store underlying data type explicitly if RTTI is disabled
|
/// Base type used to store underlying data type explicitly if RTTI is disabled
|
||||||
|
@ -576,7 +579,7 @@ class base : public std::enable_shared_from_this<base>
|
||||||
#if defined(CPPTOML_NO_RTTI)
|
#if defined(CPPTOML_NO_RTTI)
|
||||||
base_type type() const
|
base_type type() const
|
||||||
{
|
{
|
||||||
return type_;
|
return type_;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -698,7 +701,7 @@ inline std::shared_ptr<value<double>> base::as()
|
||||||
if (type() == base_type::INT)
|
if (type() == base_type::INT)
|
||||||
{
|
{
|
||||||
auto v = std::static_pointer_cast<value<int64_t>>(shared_from_this());
|
auto v = std::static_pointer_cast<value<int64_t>>(shared_from_this());
|
||||||
return make_value<double>(static_cast<double>(v->get()));;
|
return make_value<double>(static_cast<double>(v->get()));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (auto v = std::dynamic_pointer_cast<value<double>>(shared_from_this()))
|
if (auto v = std::dynamic_pointer_cast<value<double>>(shared_from_this()))
|
||||||
|
@ -731,7 +734,8 @@ inline std::shared_ptr<const value<double>> base::as() const
|
||||||
{
|
{
|
||||||
#if defined(CPPTOML_NO_RTTI)
|
#if defined(CPPTOML_NO_RTTI)
|
||||||
if (type() == base_type::FLOAT)
|
if (type() == base_type::FLOAT)
|
||||||
return std::static_pointer_cast<const value<double>>(shared_from_this());
|
return std::static_pointer_cast<const value<double>>(
|
||||||
|
shared_from_this());
|
||||||
|
|
||||||
if (type() == base_type::INT)
|
if (type() == base_type::INT)
|
||||||
{
|
{
|
||||||
|
@ -1027,11 +1031,14 @@ inline std::shared_ptr<array> make_array()
|
||||||
return std::make_shared<make_shared_enabler>();
|
return std::make_shared<make_shared_enabler>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
template <>
|
template <>
|
||||||
inline std::shared_ptr<array> make_element<array>()
|
inline std::shared_ptr<array> make_element<array>()
|
||||||
{
|
{
|
||||||
return make_array();
|
return make_array();
|
||||||
}
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a option<vector<T>>. The option will be empty if the array
|
* Obtains a option<vector<T>>. The option will be empty if the array
|
||||||
|
@ -1060,7 +1067,7 @@ class table;
|
||||||
class table_array : public base
|
class table_array : public base
|
||||||
{
|
{
|
||||||
friend class table;
|
friend class table;
|
||||||
friend std::shared_ptr<table_array> make_table_array();
|
friend std::shared_ptr<table_array> make_table_array(bool);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<base> clone() const override;
|
std::shared_ptr<base> clone() const override;
|
||||||
|
@ -1152,14 +1159,25 @@ class table_array : public base
|
||||||
array_.reserve(n);
|
array_.reserve(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the table array is declared inline. This mostly
|
||||||
|
* matters for parsing, where statically defined arrays cannot be
|
||||||
|
* appended to using the array-of-table syntax.
|
||||||
|
*/
|
||||||
|
bool is_inline() const
|
||||||
|
{
|
||||||
|
return is_inline_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#if defined(CPPTOML_NO_RTTI)
|
#if defined(CPPTOML_NO_RTTI)
|
||||||
table_array() : base(base_type::TABLE_ARRAY)
|
table_array(bool is_inline = false)
|
||||||
|
: base(base_type::TABLE_ARRAY), is_inline_(is_inline)
|
||||||
{
|
{
|
||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
table_array()
|
table_array(bool is_inline = false) : is_inline_(is_inline)
|
||||||
{
|
{
|
||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
|
@ -1169,26 +1187,30 @@ class table_array : public base
|
||||||
table_array& operator=(const table_array& rhs) = delete;
|
table_array& operator=(const table_array& rhs) = delete;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<table>> array_;
|
std::vector<std::shared_ptr<table>> array_;
|
||||||
|
const bool is_inline_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::shared_ptr<table_array> make_table_array()
|
inline std::shared_ptr<table_array> make_table_array(bool is_inline)
|
||||||
{
|
{
|
||||||
struct make_shared_enabler : public table_array
|
struct make_shared_enabler : public table_array
|
||||||
{
|
{
|
||||||
make_shared_enabler()
|
make_shared_enabler(bool mse_is_inline) : table_array(mse_is_inline)
|
||||||
{
|
{
|
||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return std::make_shared<make_shared_enabler>();
|
return std::make_shared<make_shared_enabler>(is_inline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
template <>
|
template <>
|
||||||
inline std::shared_ptr<table_array> make_element<table_array>()
|
inline std::shared_ptr<table_array> make_element<table_array>()
|
||||||
{
|
{
|
||||||
return make_table_array();
|
return make_table_array(true);
|
||||||
}
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
// The below are overloads for fetching specific value types out of a value
|
// The below are overloads for fetching specific value types out of a value
|
||||||
// where special casting behavior (like bounds checking) is desired
|
// where special casting behavior (like bounds checking) is desired
|
||||||
|
@ -1679,11 +1701,14 @@ std::shared_ptr<table> make_table()
|
||||||
return std::make_shared<make_shared_enabler>();
|
return std::make_shared<make_shared_enabler>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
template <>
|
template <>
|
||||||
inline std::shared_ptr<table> make_element<table>()
|
inline std::shared_ptr<table> make_element<table>()
|
||||||
{
|
{
|
||||||
return make_table();
|
return make_table();
|
||||||
}
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
std::shared_ptr<base> value<T>::clone() const
|
std::shared_ptr<base> value<T>::clone() const
|
||||||
|
@ -1702,7 +1727,7 @@ inline std::shared_ptr<base> array::clone() const
|
||||||
|
|
||||||
inline std::shared_ptr<base> table_array::clone() const
|
inline std::shared_ptr<base> table_array::clone() const
|
||||||
{
|
{
|
||||||
auto result = make_table_array();
|
auto result = make_table_array(is_inline());
|
||||||
result->reserve(array_.size());
|
result->reserve(array_.size());
|
||||||
for (const auto& ptr : array_)
|
for (const auto& ptr : array_)
|
||||||
result->array_.push_back(ptr->clone()->as_table());
|
result->array_.push_back(ptr->clone()->as_table());
|
||||||
|
@ -1738,6 +1763,11 @@ inline bool is_number(char c)
|
||||||
return c >= '0' && c <= '9';
|
return c >= '0' && c <= '9';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool is_hex(char c)
|
||||||
|
{
|
||||||
|
return is_number(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper object for consuming expected characters.
|
* Helper object for consuming expected characters.
|
||||||
*/
|
*/
|
||||||
|
@ -1766,6 +1796,13 @@ class consumer
|
||||||
[&](char c) { (*this)(c); });
|
[&](char c) { (*this)(c); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void eat_or(char a, char b)
|
||||||
|
{
|
||||||
|
if (it_ == end_ || (*it_ != a && *it_ != b))
|
||||||
|
on_error_();
|
||||||
|
++it_;
|
||||||
|
}
|
||||||
|
|
||||||
int eat_digits(int len)
|
int eat_digits(int len)
|
||||||
{
|
{
|
||||||
int val = 0;
|
int val = 0;
|
||||||
|
@ -1830,7 +1867,7 @@ inline std::istream& getline(std::istream& input, std::string& line)
|
||||||
line.push_back(static_cast<char>(c));
|
line.push_back(static_cast<char>(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // namespace detail
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The parser class.
|
* The parser class.
|
||||||
|
@ -1914,21 +1951,25 @@ class parser
|
||||||
|
|
||||||
std::string full_table_name;
|
std::string full_table_name;
|
||||||
bool inserted = false;
|
bool inserted = false;
|
||||||
while (it != end && *it != ']')
|
|
||||||
{
|
|
||||||
auto part = parse_key(it, end,
|
|
||||||
[](char c) { return c == '.' || c == ']'; });
|
|
||||||
|
|
||||||
|
auto key_end = [](char c) { return c == ']'; };
|
||||||
|
|
||||||
|
auto key_part_handler = [&](const std::string& part) {
|
||||||
if (part.empty())
|
if (part.empty())
|
||||||
throw_parse_exception("Empty component of table name");
|
throw_parse_exception("Empty component of table name");
|
||||||
|
|
||||||
if (!full_table_name.empty())
|
if (!full_table_name.empty())
|
||||||
full_table_name += ".";
|
full_table_name += '.';
|
||||||
full_table_name += part;
|
full_table_name += part;
|
||||||
|
|
||||||
if (curr_table->contains(part))
|
if (curr_table->contains(part))
|
||||||
{
|
{
|
||||||
|
#if !defined(__PGI)
|
||||||
auto b = curr_table->get(part);
|
auto b = curr_table->get(part);
|
||||||
|
#else
|
||||||
|
// Workaround for PGI compiler
|
||||||
|
std::shared_ptr<base> b = curr_table->get(part);
|
||||||
|
#endif
|
||||||
if (b->is_table())
|
if (b->is_table())
|
||||||
curr_table = static_cast<table*>(b.get());
|
curr_table = static_cast<table*>(b.get());
|
||||||
else if (b->is_table_array())
|
else if (b->is_table_array())
|
||||||
|
@ -1946,16 +1987,23 @@ class parser
|
||||||
curr_table->insert(part, make_table());
|
curr_table->insert(part, make_table());
|
||||||
curr_table = static_cast<table*>(curr_table->get(part).get());
|
curr_table = static_cast<table*>(curr_table->get(part).get());
|
||||||
}
|
}
|
||||||
consume_whitespace(it, end);
|
};
|
||||||
if (it != end && *it == '.')
|
|
||||||
++it;
|
key_part_handler(parse_key(it, end, key_end, key_part_handler));
|
||||||
consume_whitespace(it, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it == end)
|
if (it == end)
|
||||||
throw_parse_exception(
|
throw_parse_exception(
|
||||||
"Unterminated table declaration; did you forget a ']'?");
|
"Unterminated table declaration; did you forget a ']'?");
|
||||||
|
|
||||||
|
if (*it != ']')
|
||||||
|
{
|
||||||
|
std::string errmsg{"Unexpected character in table definition: "};
|
||||||
|
errmsg += '"';
|
||||||
|
errmsg += *it;
|
||||||
|
errmsg += '"';
|
||||||
|
throw_parse_exception(errmsg);
|
||||||
|
}
|
||||||
|
|
||||||
// table already existed
|
// table already existed
|
||||||
if (!inserted)
|
if (!inserted)
|
||||||
{
|
{
|
||||||
|
@ -1969,8 +2017,9 @@ class parser
|
||||||
// since it has already been defined. If there aren't any
|
// since it has already been defined. If there aren't any
|
||||||
// values, then it was implicitly created by something like
|
// values, then it was implicitly created by something like
|
||||||
// [a.b]
|
// [a.b]
|
||||||
if (curr_table->empty() || std::any_of(curr_table->begin(),
|
if (curr_table->empty()
|
||||||
curr_table->end(), is_value))
|
|| std::any_of(curr_table->begin(), curr_table->end(),
|
||||||
|
is_value))
|
||||||
{
|
{
|
||||||
throw_parse_exception("Redefinition of table "
|
throw_parse_exception("Redefinition of table "
|
||||||
+ full_table_name);
|
+ full_table_name);
|
||||||
|
@ -1989,36 +2038,45 @@ class parser
|
||||||
if (it == end || *it == ']')
|
if (it == end || *it == ']')
|
||||||
throw_parse_exception("Table array name cannot be empty");
|
throw_parse_exception("Table array name cannot be empty");
|
||||||
|
|
||||||
std::string full_ta_name;
|
auto key_end = [](char c) { return c == ']'; };
|
||||||
while (it != end && *it != ']')
|
|
||||||
{
|
|
||||||
auto part = parse_key(it, end,
|
|
||||||
[](char c) { return c == '.' || c == ']'; });
|
|
||||||
|
|
||||||
|
std::string full_ta_name;
|
||||||
|
auto key_part_handler = [&](const std::string& part) {
|
||||||
if (part.empty())
|
if (part.empty())
|
||||||
throw_parse_exception("Empty component of table array name");
|
throw_parse_exception("Empty component of table array name");
|
||||||
|
|
||||||
if (!full_ta_name.empty())
|
if (!full_ta_name.empty())
|
||||||
full_ta_name += ".";
|
full_ta_name += '.';
|
||||||
full_ta_name += part;
|
full_ta_name += part;
|
||||||
|
|
||||||
consume_whitespace(it, end);
|
|
||||||
if (it != end && *it == '.')
|
|
||||||
++it;
|
|
||||||
consume_whitespace(it, end);
|
|
||||||
|
|
||||||
if (curr_table->contains(part))
|
if (curr_table->contains(part))
|
||||||
{
|
{
|
||||||
|
#if !defined(__PGI)
|
||||||
auto b = curr_table->get(part);
|
auto b = curr_table->get(part);
|
||||||
|
#else
|
||||||
|
// Workaround for PGI compiler
|
||||||
|
std::shared_ptr<base> b = curr_table->get(part);
|
||||||
|
#endif
|
||||||
|
|
||||||
// if this is the end of the table array name, add an
|
// if this is the end of the table array name, add an
|
||||||
// element to the table array that we just looked up
|
// element to the table array that we just looked up,
|
||||||
|
// provided it was not declared inline
|
||||||
if (it != end && *it == ']')
|
if (it != end && *it == ']')
|
||||||
{
|
{
|
||||||
if (!b->is_table_array())
|
if (!b->is_table_array())
|
||||||
|
{
|
||||||
throw_parse_exception("Key " + full_ta_name
|
throw_parse_exception("Key " + full_ta_name
|
||||||
+ " is not a table array");
|
+ " is not a table array");
|
||||||
|
}
|
||||||
|
|
||||||
auto v = b->as_table_array();
|
auto v = b->as_table_array();
|
||||||
|
|
||||||
|
if (v->is_inline())
|
||||||
|
{
|
||||||
|
throw_parse_exception("Static array " + full_ta_name
|
||||||
|
+ " cannot be appended to");
|
||||||
|
}
|
||||||
|
|
||||||
v->get().push_back(make_table());
|
v->get().push_back(make_table());
|
||||||
curr_table = v->get().back().get();
|
curr_table = v->get().back().get();
|
||||||
}
|
}
|
||||||
|
@ -2059,15 +2117,16 @@ class parser
|
||||||
= static_cast<table*>(curr_table->get(part).get());
|
= static_cast<table*>(curr_table->get(part).get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
key_part_handler(parse_key(it, end, key_end, key_part_handler));
|
||||||
|
|
||||||
// consume the last "]]"
|
// consume the last "]]"
|
||||||
if (it == end)
|
auto eat = make_consumer(it, end, [this]() {
|
||||||
throw_parse_exception("Unterminated table array name");
|
throw_parse_exception("Unterminated table array name");
|
||||||
++it;
|
});
|
||||||
if (it == end)
|
eat(']');
|
||||||
throw_parse_exception("Unterminated table array name");
|
eat(']');
|
||||||
++it;
|
|
||||||
|
|
||||||
consume_whitespace(it, end);
|
consume_whitespace(it, end);
|
||||||
eol_or_comment(it, end);
|
eol_or_comment(it, end);
|
||||||
|
@ -2076,7 +2135,35 @@ class parser
|
||||||
void parse_key_value(std::string::iterator& it, std::string::iterator& end,
|
void parse_key_value(std::string::iterator& it, std::string::iterator& end,
|
||||||
table* curr_table)
|
table* curr_table)
|
||||||
{
|
{
|
||||||
auto key = parse_key(it, end, [](char c) { return c == '='; });
|
auto key_end = [](char c) { return c == '='; };
|
||||||
|
|
||||||
|
auto key_part_handler = [&](const std::string& part) {
|
||||||
|
// two cases: this key part exists already, in which case it must
|
||||||
|
// be a table, or it doesn't exist in which case we must create
|
||||||
|
// an implicitly defined table
|
||||||
|
if (curr_table->contains(part))
|
||||||
|
{
|
||||||
|
auto val = curr_table->get(part);
|
||||||
|
if (val->is_table())
|
||||||
|
{
|
||||||
|
curr_table = static_cast<table*>(val.get());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw_parse_exception("Key " + part
|
||||||
|
+ " already exists as a value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto newtable = make_table();
|
||||||
|
curr_table->insert(part, newtable);
|
||||||
|
curr_table = newtable.get();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto key = parse_key(it, end, key_end, key_part_handler);
|
||||||
|
|
||||||
if (curr_table->contains(key))
|
if (curr_table->contains(key))
|
||||||
throw_parse_exception("Key " + key + " already present");
|
throw_parse_exception("Key " + key + " already present");
|
||||||
if (it == end || *it != '=')
|
if (it == end || *it != '=')
|
||||||
|
@ -2087,18 +2174,57 @@ class parser
|
||||||
consume_whitespace(it, end);
|
consume_whitespace(it, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Function>
|
template <class KeyEndFinder, class KeyPartHandler>
|
||||||
std::string parse_key(std::string::iterator& it,
|
std::string
|
||||||
const std::string::iterator& end, Function&& fun)
|
parse_key(std::string::iterator& it, const std::string::iterator& end,
|
||||||
|
KeyEndFinder&& key_end, KeyPartHandler&& key_part_handler)
|
||||||
|
{
|
||||||
|
// parse the key as a series of one or more simple-keys joined with '.'
|
||||||
|
while (it != end && !key_end(*it))
|
||||||
|
{
|
||||||
|
auto part = parse_simple_key(it, end);
|
||||||
|
consume_whitespace(it, end);
|
||||||
|
|
||||||
|
if (it == end || key_end(*it))
|
||||||
|
{
|
||||||
|
return part;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*it != '.')
|
||||||
|
{
|
||||||
|
std::string errmsg{"Unexpected character in key: "};
|
||||||
|
errmsg += '"';
|
||||||
|
errmsg += *it;
|
||||||
|
errmsg += '"';
|
||||||
|
throw_parse_exception(errmsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
key_part_handler(part);
|
||||||
|
|
||||||
|
// consume the dot
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw_parse_exception("Unexpected end of key");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string parse_simple_key(std::string::iterator& it,
|
||||||
|
const std::string::iterator& end)
|
||||||
{
|
{
|
||||||
consume_whitespace(it, end);
|
consume_whitespace(it, end);
|
||||||
if (*it == '"')
|
|
||||||
|
if (it == end)
|
||||||
|
throw_parse_exception("Unexpected end of key (blank key?)");
|
||||||
|
|
||||||
|
if (*it == '"' || *it == '\'')
|
||||||
{
|
{
|
||||||
return parse_quoted_key(it, end);
|
return string_literal(it, end, *it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto bke = std::find_if(it, end, std::forward<Function>(fun));
|
auto bke = std::find_if(it, end, [](char c) {
|
||||||
|
return c == '.' || c == '=' || c == ']';
|
||||||
|
});
|
||||||
return parse_bare_key(it, bke);
|
return parse_bare_key(it, bke);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2142,12 +2268,6 @@ class parser
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string parse_quoted_key(std::string::iterator& it,
|
|
||||||
const std::string::iterator& end)
|
|
||||||
{
|
|
||||||
return string_literal(it, end, '"');
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class parse_type
|
enum class parse_type
|
||||||
{
|
{
|
||||||
STRING = 1,
|
STRING = 1,
|
||||||
|
@ -2193,7 +2313,7 @@ class parser
|
||||||
parse_type determine_value_type(const std::string::iterator& it,
|
parse_type determine_value_type(const std::string::iterator& it,
|
||||||
const std::string::iterator& end)
|
const std::string::iterator& end)
|
||||||
{
|
{
|
||||||
if(it == end)
|
if (it == end)
|
||||||
{
|
{
|
||||||
throw_parse_exception("Failed to parse value type");
|
throw_parse_exception("Failed to parse value type");
|
||||||
}
|
}
|
||||||
|
@ -2209,7 +2329,11 @@ class parser
|
||||||
{
|
{
|
||||||
return *dtype;
|
return *dtype;
|
||||||
}
|
}
|
||||||
else if (is_number(*it) || *it == '-' || *it == '+')
|
else if (is_number(*it) || *it == '-' || *it == '+'
|
||||||
|
|| (*it == 'i' && it + 1 != end && it[1] == 'n'
|
||||||
|
&& it + 2 != end && it[2] == 'f')
|
||||||
|
|| (*it == 'n' && it + 1 != end && it[1] == 'a'
|
||||||
|
&& it + 2 != end && it[2] == 'n'))
|
||||||
{
|
{
|
||||||
return determine_number_type(it, end);
|
return determine_number_type(it, end);
|
||||||
}
|
}
|
||||||
|
@ -2235,6 +2359,13 @@ class parser
|
||||||
auto check_it = it;
|
auto check_it = it;
|
||||||
if (*check_it == '-' || *check_it == '+')
|
if (*check_it == '-' || *check_it == '+')
|
||||||
++check_it;
|
++check_it;
|
||||||
|
|
||||||
|
if (check_it == end)
|
||||||
|
throw_parse_exception("Malformed number");
|
||||||
|
|
||||||
|
if (*check_it == 'i' || *check_it == 'n')
|
||||||
|
return parse_type::FLOAT;
|
||||||
|
|
||||||
while (check_it != end && is_number(*check_it))
|
while (check_it != end && is_number(*check_it))
|
||||||
++check_it;
|
++check_it;
|
||||||
if (check_it != end && *check_it == '.')
|
if (check_it != end && *check_it == '.')
|
||||||
|
@ -2283,57 +2414,56 @@ class parser
|
||||||
bool consuming = false;
|
bool consuming = false;
|
||||||
std::shared_ptr<value<std::string>> ret;
|
std::shared_ptr<value<std::string>> ret;
|
||||||
|
|
||||||
auto handle_line
|
auto handle_line = [&](std::string::iterator& local_it,
|
||||||
= [&](std::string::iterator& local_it,
|
std::string::iterator& local_end) {
|
||||||
std::string::iterator& local_end) {
|
if (consuming)
|
||||||
if (consuming)
|
{
|
||||||
{
|
local_it = std::find_if_not(local_it, local_end, is_ws);
|
||||||
local_it = std::find_if_not(local_it, local_end, is_ws);
|
|
||||||
|
|
||||||
// whole line is whitespace
|
// whole line is whitespace
|
||||||
if (local_it == local_end)
|
if (local_it == local_end)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
consuming = false;
|
consuming = false;
|
||||||
|
|
||||||
while (local_it != local_end)
|
while (local_it != local_end)
|
||||||
{
|
{
|
||||||
// handle escaped characters
|
// handle escaped characters
|
||||||
if (delim == '"' && *local_it == '\\')
|
if (delim == '"' && *local_it == '\\')
|
||||||
{
|
{
|
||||||
auto check = local_it;
|
auto check = local_it;
|
||||||
// check if this is an actual escape sequence or a
|
// check if this is an actual escape sequence or a
|
||||||
// whitespace escaping backslash
|
// whitespace escaping backslash
|
||||||
++check;
|
++check;
|
||||||
consume_whitespace(check, local_end);
|
consume_whitespace(check, local_end);
|
||||||
if (check == local_end)
|
if (check == local_end)
|
||||||
{
|
{
|
||||||
consuming = true;
|
consuming = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ss << parse_escape_code(local_it, local_end);
|
ss << parse_escape_code(local_it, local_end);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we can end the string
|
// if we can end the string
|
||||||
if (std::distance(local_it, local_end) >= 3)
|
if (std::distance(local_it, local_end) >= 3)
|
||||||
{
|
{
|
||||||
auto check = local_it;
|
auto check = local_it;
|
||||||
// check for """
|
// check for """
|
||||||
if (*check++ == delim && *check++ == delim
|
if (*check++ == delim && *check++ == delim
|
||||||
&& *check++ == delim)
|
&& *check++ == delim)
|
||||||
{
|
{
|
||||||
local_it = check;
|
local_it = check;
|
||||||
ret = make_value<std::string>(ss.str());
|
ret = make_value<std::string>(ss.str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ss << *local_it++;
|
ss << *local_it++;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// handle the remainder of the current line
|
// handle the remainder of the current line
|
||||||
handle_line(it, end);
|
handle_line(it, end);
|
||||||
|
@ -2514,17 +2644,13 @@ class parser
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_hex(char c)
|
|
||||||
{
|
|
||||||
return is_number(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t hex_to_digit(char c)
|
uint32_t hex_to_digit(char c)
|
||||||
{
|
{
|
||||||
if (is_number(c))
|
if (is_number(c))
|
||||||
return static_cast<uint32_t>(c - '0');
|
return static_cast<uint32_t>(c - '0');
|
||||||
return 10 + static_cast<uint32_t>(
|
return 10
|
||||||
c - ((c >= 'a' && c <= 'f') ? 'a' : 'A'));
|
+ static_cast<uint32_t>(c
|
||||||
|
- ((c >= 'a' && c <= 'f') ? 'a' : 'A'));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<base> parse_number(std::string::iterator& it,
|
std::shared_ptr<base> parse_number(std::string::iterator& it,
|
||||||
|
@ -2538,25 +2664,6 @@ class parser
|
||||||
++check_it;
|
++check_it;
|
||||||
};
|
};
|
||||||
|
|
||||||
eat_sign();
|
|
||||||
|
|
||||||
auto eat_numbers = [&]() {
|
|
||||||
auto beg = check_it;
|
|
||||||
while (check_it != end && is_number(*check_it))
|
|
||||||
{
|
|
||||||
++check_it;
|
|
||||||
if (check_it != end && *check_it == '_')
|
|
||||||
{
|
|
||||||
++check_it;
|
|
||||||
if (check_it == end || !is_number(*check_it))
|
|
||||||
throw_parse_exception("Malformed number");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (check_it == beg)
|
|
||||||
throw_parse_exception("Malformed number");
|
|
||||||
};
|
|
||||||
|
|
||||||
auto check_no_leading_zero = [&]() {
|
auto check_no_leading_zero = [&]() {
|
||||||
if (check_it != end && *check_it == '0' && check_it + 1 != check_end
|
if (check_it != end && *check_it == '0' && check_it + 1 != check_end
|
||||||
&& check_it[1] != '.')
|
&& check_it[1] != '.')
|
||||||
|
@ -2565,7 +2672,80 @@ class parser
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto eat_digits = [&](bool (*check_char)(char)) {
|
||||||
|
auto beg = check_it;
|
||||||
|
while (check_it != end && check_char(*check_it))
|
||||||
|
{
|
||||||
|
++check_it;
|
||||||
|
if (check_it != end && *check_it == '_')
|
||||||
|
{
|
||||||
|
++check_it;
|
||||||
|
if (check_it == end || !check_char(*check_it))
|
||||||
|
throw_parse_exception("Malformed number");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_it == beg)
|
||||||
|
throw_parse_exception("Malformed number");
|
||||||
|
};
|
||||||
|
|
||||||
|
auto eat_hex = [&]() { eat_digits(&is_hex); };
|
||||||
|
|
||||||
|
auto eat_numbers = [&]() { eat_digits(&is_number); };
|
||||||
|
|
||||||
|
if (check_it != end && *check_it == '0' && check_it + 1 != check_end
|
||||||
|
&& (check_it[1] == 'x' || check_it[1] == 'o' || check_it[1] == 'b'))
|
||||||
|
{
|
||||||
|
++check_it;
|
||||||
|
char base = *check_it;
|
||||||
|
++check_it;
|
||||||
|
if (base == 'x')
|
||||||
|
{
|
||||||
|
eat_hex();
|
||||||
|
return parse_int(it, check_it, 16);
|
||||||
|
}
|
||||||
|
else if (base == 'o')
|
||||||
|
{
|
||||||
|
auto start = check_it;
|
||||||
|
eat_numbers();
|
||||||
|
auto val = parse_int(start, check_it, 8, "0");
|
||||||
|
it = start;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
else // if (base == 'b')
|
||||||
|
{
|
||||||
|
auto start = check_it;
|
||||||
|
eat_numbers();
|
||||||
|
auto val = parse_int(start, check_it, 2);
|
||||||
|
it = start;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eat_sign();
|
||||||
check_no_leading_zero();
|
check_no_leading_zero();
|
||||||
|
|
||||||
|
if (check_it != end && check_it + 1 != end && check_it + 2 != end)
|
||||||
|
{
|
||||||
|
if (check_it[0] == 'i' && check_it[1] == 'n' && check_it[2] == 'f')
|
||||||
|
{
|
||||||
|
auto val = std::numeric_limits<double>::infinity();
|
||||||
|
if (*it == '-')
|
||||||
|
val = -val;
|
||||||
|
it = check_it + 3;
|
||||||
|
return make_value(val);
|
||||||
|
}
|
||||||
|
else if (check_it[0] == 'n' && check_it[1] == 'a'
|
||||||
|
&& check_it[2] == 'n')
|
||||||
|
{
|
||||||
|
auto val = std::numeric_limits<double>::quiet_NaN();
|
||||||
|
if (*it == '-')
|
||||||
|
val = -val;
|
||||||
|
it = check_it + 3;
|
||||||
|
return make_value(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
eat_numbers();
|
eat_numbers();
|
||||||
|
|
||||||
if (check_it != end
|
if (check_it != end
|
||||||
|
@ -2604,14 +2784,17 @@ class parser
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<value<int64_t>> parse_int(std::string::iterator& it,
|
std::shared_ptr<value<int64_t>> parse_int(std::string::iterator& it,
|
||||||
const std::string::iterator& end)
|
const std::string::iterator& end,
|
||||||
|
int base = 10,
|
||||||
|
const char* prefix = "")
|
||||||
{
|
{
|
||||||
std::string v{it, end};
|
std::string v{it, end};
|
||||||
|
v = prefix + v;
|
||||||
v.erase(std::remove(v.begin(), v.end(), '_'), v.end());
|
v.erase(std::remove(v.begin(), v.end(), '_'), v.end());
|
||||||
it = end;
|
it = end;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return make_value<int64_t>(std::stoll(v));
|
return make_value<int64_t>(std::stoll(v, nullptr, base));
|
||||||
}
|
}
|
||||||
catch (const std::invalid_argument& ex)
|
catch (const std::invalid_argument& ex)
|
||||||
{
|
{
|
||||||
|
@ -2674,18 +2857,33 @@ class parser
|
||||||
std::string::iterator find_end_of_number(std::string::iterator it,
|
std::string::iterator find_end_of_number(std::string::iterator it,
|
||||||
std::string::iterator end)
|
std::string::iterator end)
|
||||||
{
|
{
|
||||||
return std::find_if(it, end, [](char c) {
|
auto ret = std::find_if(it, end, [](char c) {
|
||||||
return !is_number(c) && c != '_' && c != '.' && c != 'e' && c != 'E'
|
return !is_number(c) && c != '_' && c != '.' && c != 'e' && c != 'E'
|
||||||
&& c != '-' && c != '+';
|
&& c != '-' && c != '+' && c != 'x' && c != 'o' && c != 'b';
|
||||||
});
|
});
|
||||||
|
if (ret != end && ret + 1 != end && ret + 2 != end)
|
||||||
|
{
|
||||||
|
if ((ret[0] == 'i' && ret[1] == 'n' && ret[2] == 'f')
|
||||||
|
|| (ret[0] == 'n' && ret[1] == 'a' && ret[2] == 'n'))
|
||||||
|
{
|
||||||
|
ret = ret + 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string::iterator find_end_of_date(std::string::iterator it,
|
std::string::iterator find_end_of_date(std::string::iterator it,
|
||||||
std::string::iterator end)
|
std::string::iterator end)
|
||||||
{
|
{
|
||||||
return std::find_if(it, end, [](char c) {
|
auto end_of_date = std::find_if(it, end, [](char c) {
|
||||||
return !is_number(c) && c != 'T' && c != 'Z' && c != ':' && c != '-'
|
return !is_number(c) && c != '-';
|
||||||
&& c != '+' && c != '.';
|
});
|
||||||
|
if (end_of_date != end && *end_of_date == ' ' && end_of_date + 1 != end
|
||||||
|
&& is_number(end_of_date[1]))
|
||||||
|
end_of_date++;
|
||||||
|
return std::find_if(end_of_date, end, [](char c) {
|
||||||
|
return !is_number(c) && c != 'T' && c != 'Z' && c != ':'
|
||||||
|
&& c != '-' && c != '+' && c != '.';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2754,7 +2952,7 @@ class parser
|
||||||
if (it == date_end)
|
if (it == date_end)
|
||||||
return make_value(ldate);
|
return make_value(ldate);
|
||||||
|
|
||||||
eat('T');
|
eat.eat_or('T', ' ');
|
||||||
|
|
||||||
local_datetime ldt;
|
local_datetime ldt;
|
||||||
static_cast<local_date&>(ldt) = ldate;
|
static_cast<local_date&>(ldt) = ldate;
|
||||||
|
@ -2850,9 +3048,9 @@ class parser
|
||||||
auto arr = make_array();
|
auto arr = make_array();
|
||||||
while (it != end && *it != ']')
|
while (it != end && *it != ']')
|
||||||
{
|
{
|
||||||
auto value = parse_value(it, end);
|
auto val = parse_value(it, end);
|
||||||
if (auto v = value->as<Value>())
|
if (auto v = val->as<Value>())
|
||||||
arr->get().push_back(value);
|
arr->get().push_back(val);
|
||||||
else
|
else
|
||||||
throw_parse_exception("Arrays must be homogeneous");
|
throw_parse_exception("Arrays must be homogeneous");
|
||||||
skip_whitespace_and_comments(it, end);
|
skip_whitespace_and_comments(it, end);
|
||||||
|
@ -2871,7 +3069,7 @@ class parser
|
||||||
std::string::iterator& it,
|
std::string::iterator& it,
|
||||||
std::string::iterator& end)
|
std::string::iterator& end)
|
||||||
{
|
{
|
||||||
auto arr = make_element<Object>();
|
auto arr = detail::make_element<Object>();
|
||||||
|
|
||||||
while (it != end && *it != ']')
|
while (it != end && *it != ']')
|
||||||
{
|
{
|
||||||
|
@ -2881,7 +3079,7 @@ class parser
|
||||||
arr->get().push_back(((*this).*fun)(it, end));
|
arr->get().push_back(((*this).*fun)(it, end));
|
||||||
skip_whitespace_and_comments(it, end);
|
skip_whitespace_and_comments(it, end);
|
||||||
|
|
||||||
if (*it != ',')
|
if (it == end || *it != ',')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
++it;
|
++it;
|
||||||
|
@ -2906,8 +3104,11 @@ class parser
|
||||||
throw_parse_exception("Unterminated inline table");
|
throw_parse_exception("Unterminated inline table");
|
||||||
|
|
||||||
consume_whitespace(it, end);
|
consume_whitespace(it, end);
|
||||||
parse_key_value(it, end, tbl.get());
|
if (it != end && *it != '}')
|
||||||
consume_whitespace(it, end);
|
{
|
||||||
|
parse_key_value(it, end, tbl.get());
|
||||||
|
consume_whitespace(it, end);
|
||||||
|
}
|
||||||
} while (*it == ',');
|
} while (*it == ',');
|
||||||
|
|
||||||
if (it == end || *it != '}')
|
if (it == end || *it != '}')
|
||||||
|
@ -2987,7 +3188,8 @@ class parser
|
||||||
if (it[4] != '-' || it[7] != '-')
|
if (it[4] != '-' || it[7] != '-')
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (len >= 19 && it[10] == 'T' && is_time(it + 11, date_end))
|
if (len >= 19 && (it[10] == 'T' || it[10] == ' ')
|
||||||
|
&& is_time(it + 11, date_end))
|
||||||
{
|
{
|
||||||
// datetime type
|
// datetime type
|
||||||
auto time_end = find_end_of_time(it + 11, date_end);
|
auto time_end = find_end_of_time(it + 11, date_end);
|
||||||
|
@ -3243,7 +3445,7 @@ class toml_writer
|
||||||
{
|
{
|
||||||
res += "\\\\";
|
res += "\\\\";
|
||||||
}
|
}
|
||||||
else if ((const uint32_t)*it <= 0x001f)
|
else if (static_cast<uint32_t>(*it) <= UINT32_C(0x001f))
|
||||||
{
|
{
|
||||||
res += "\\u";
|
res += "\\u";
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -3274,12 +3476,21 @@ class toml_writer
|
||||||
*/
|
*/
|
||||||
void write(const value<double>& v)
|
void write(const value<double>& v)
|
||||||
{
|
{
|
||||||
std::ios::fmtflags flags{stream_.flags()};
|
std::stringstream ss;
|
||||||
|
ss << std::showpoint
|
||||||
|
<< std::setprecision(std::numeric_limits<double>::max_digits10)
|
||||||
|
<< v.get();
|
||||||
|
|
||||||
stream_ << std::showpoint;
|
auto double_str = ss.str();
|
||||||
write(v.get());
|
auto pos = double_str.find("e0");
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
double_str.replace(pos, 2, "e");
|
||||||
|
pos = double_str.find("e-0");
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
double_str.replace(pos, 3, "e-");
|
||||||
|
|
||||||
stream_.flags(flags);
|
stream_ << double_str;
|
||||||
|
has_naked_endline_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3287,9 +3498,9 @@ class toml_writer
|
||||||
* offset_datetime.
|
* offset_datetime.
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T>
|
||||||
typename std::enable_if<is_one_of<T, int64_t, local_date, local_time,
|
typename std::enable_if<
|
||||||
local_datetime,
|
is_one_of<T, int64_t, local_date, local_time, local_datetime,
|
||||||
offset_datetime>::value>::type
|
offset_datetime>::value>::type
|
||||||
write(const value<T>& v)
|
write(const value<T>& v)
|
||||||
{
|
{
|
||||||
write(v.get());
|
write(v.get());
|
||||||
|
@ -3453,5 +3664,5 @@ inline std::ostream& operator<<(std::ostream& stream, const array& a)
|
||||||
a.accept(writer);
|
a.accept(writer);
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
}
|
} // namespace cpptoml
|
||||||
#endif
|
#endif // CPPTOML_H
|
||||||
|
|
|
@ -81,6 +81,8 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
|
||||||
AttrPath::iterator i;
|
AttrPath::iterator i;
|
||||||
// All attrpaths have at least one attr
|
// All attrpaths have at least one attr
|
||||||
assert(!attrPath.empty());
|
assert(!attrPath.empty());
|
||||||
|
// Checking attrPath validity.
|
||||||
|
// ===========================
|
||||||
for (i = attrPath.begin(); i + 1 < attrPath.end(); i++) {
|
for (i = attrPath.begin(); i + 1 < attrPath.end(); i++) {
|
||||||
if (i->symbol.set()) {
|
if (i->symbol.set()) {
|
||||||
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
|
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
|
||||||
|
@ -102,11 +104,29 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
|
||||||
attrs = nested;
|
attrs = nested;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Expr insertion.
|
||||||
|
// ==========================
|
||||||
if (i->symbol.set()) {
|
if (i->symbol.set()) {
|
||||||
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
|
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
|
||||||
if (j != attrs->attrs.end()) {
|
if (j != attrs->attrs.end()) {
|
||||||
dupAttr(attrPath, pos, j->second.pos);
|
// This attr path is already defined. However, if both
|
||||||
|
// e and the expr pointed by the attr path are two attribute sets,
|
||||||
|
// we want to merge them.
|
||||||
|
// Otherwise, throw an error.
|
||||||
|
auto ae = dynamic_cast<ExprAttrs *>(e);
|
||||||
|
auto jAttrs = dynamic_cast<ExprAttrs *>(j->second.e);
|
||||||
|
if (jAttrs && ae) {
|
||||||
|
for (auto & ad : ae->attrs) {
|
||||||
|
auto j2 = jAttrs->attrs.find(ad.first);
|
||||||
|
if (j2 != jAttrs->attrs.end()) // Attr already defined in iAttrs, error.
|
||||||
|
dupAttr(ad.first, j2->second.pos, ad.second.pos);
|
||||||
|
jAttrs->attrs[ad.first] = ad.second;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dupAttr(attrPath, pos, j->second.pos);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// This attr path is not defined. Let's create it.
|
||||||
attrs->attrs[i->symbol] = ExprAttrs::AttrDef(e, pos);
|
attrs->attrs[i->symbol] = ExprAttrs::AttrDef(e, pos);
|
||||||
e->setName(i->symbol);
|
e->setName(i->symbol);
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,11 +352,18 @@ public:
|
||||||
|
|
||||||
if (running || done || expected || failed) {
|
if (running || done || expected || failed) {
|
||||||
if (running)
|
if (running)
|
||||||
s = fmt(ANSI_BLUE + numberFmt + ANSI_NORMAL "/" ANSI_GREEN + numberFmt + ANSI_NORMAL "/" + numberFmt,
|
if (expected != 0)
|
||||||
running / unit, done / unit, expected / unit);
|
s = fmt(ANSI_BLUE + numberFmt + ANSI_NORMAL "/" ANSI_GREEN + numberFmt + ANSI_NORMAL "/" + numberFmt,
|
||||||
|
running / unit, done / unit, expected / unit);
|
||||||
|
else
|
||||||
|
s = fmt(ANSI_BLUE + numberFmt + ANSI_NORMAL "/" ANSI_GREEN + numberFmt + ANSI_NORMAL,
|
||||||
|
running / unit, done / unit);
|
||||||
else if (expected != done)
|
else if (expected != done)
|
||||||
s = fmt(ANSI_GREEN + numberFmt + ANSI_NORMAL "/" + numberFmt,
|
if (expected != 0)
|
||||||
done / unit, expected / unit);
|
s = fmt(ANSI_GREEN + numberFmt + ANSI_NORMAL "/" + numberFmt,
|
||||||
|
done / unit, expected / unit);
|
||||||
|
else
|
||||||
|
s = fmt(ANSI_GREEN + numberFmt + ANSI_NORMAL, done / unit);
|
||||||
else
|
else
|
||||||
s = fmt(done ? ANSI_GREEN + numberFmt + ANSI_NORMAL : numberFmt, done / unit);
|
s = fmt(done ? ANSI_GREEN + numberFmt + ANSI_NORMAL : numberFmt, done / unit);
|
||||||
s = fmt(itemFmt, s);
|
s = fmt(itemFmt, s);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
[ { clients = { data = [ [ "gamma" "delta" ] [ 1 2 ] ]; hosts = [ "alpha" "omega" ]; }; database = { connection_max = 5000; enabled = true; ports = [ 8001 8001 8002 ]; server = "192.168.1.1"; }; owner = { name = "Tom Preston-Werner"; }; servers = { alpha = { dc = "eqdc10"; ip = "10.0.0.1"; }; beta = { dc = "eqdc10"; ip = "10.0.0.2"; }; }; title = "TOML Example"; } { "'key2'" = "value"; "1234" = "value"; "127.0.0.1" = "value"; a = { b = { c = { }; }; }; arr1 = [ 1 2 3 ]; arr2 = [ "red" "yellow" "green" ]; arr3 = [ [ 1 2 ] [ 3 4 5 ] ]; arr4 = [ "all" "strings" "are the same" "type" ]; arr5 = [ [ 1 2 ] [ "a" "b" "c" ] ]; arr7 = [ 1 2 3 ]; arr8 = [ 1 2 ]; bare-key = "value"; bare_key = "value"; bool1 = true; bool2 = false; "character encoding" = "value"; d = { e = { f = { }; }; }; flt1 = 1; flt2 = 3.1415; flt3 = -0.01; flt4 = 5e+22; flt5 = 1e+06; flt6 = -0.02; flt7 = 6.626e-34; flt8 = 9.22462e+06; g = { h = { i = { }; }; }; int1 = 99; int2 = 42; int3 = 0; int4 = -17; int5 = 1000; int6 = 5349221; int7 = 12345; j = { "ʞ" = { "'l'" = { }; }; }; key = "value"; name = "Orange"; products = [ { name = "Hammer"; sku = 738594937; } { } { color = "gray"; name = "Nail"; sku = 284758393; } ]; str = "I'm a string. \"You can quote me\". Name\tJosé\nLocation\tSF."; table-1 = { key1 = "some string"; key2 = 123; }; table-2 = { key1 = "another string"; key2 = 456; }; x = { y = { z = { w = { name = { first = "Tom"; last = "Preston-Werner"; }; point = { x = 1; y = 2; }; }; }; }; }; "ʎǝʞ" = "value"; } { metadata = { "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"; "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"; "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"; "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"; }; package = [ { dependencies = [ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" ]; name = "aho-corasick"; source = "registry+https://github.com/rust-lang/crates.io-index"; version = "0.6.4"; } { name = "ansi_term"; source = "registry+https://github.com/rust-lang/crates.io-index"; version = "0.9.0"; } { dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" ]; name = "atty"; source = "registry+https://github.com/rust-lang/crates.io-index"; version = "0.2.10"; } ]; } ]
|
[ { clients = { data = [ [ "gamma" "delta" ] [ 1 2 ] ]; hosts = [ "alpha" "omega" ]; }; database = { connection_max = 5000; enabled = true; ports = [ 8001 8001 8002 ]; server = "192.168.1.1"; }; owner = { name = "Tom Preston-Werner"; }; servers = { alpha = { dc = "eqdc10"; ip = "10.0.0.1"; }; beta = { dc = "eqdc10"; ip = "10.0.0.2"; }; }; title = "TOML Example"; } { "1234" = "value"; "127.0.0.1" = "value"; a = { b = { c = { }; }; }; arr1 = [ 1 2 3 ]; arr2 = [ "red" "yellow" "green" ]; arr3 = [ [ 1 2 ] [ 3 4 5 ] ]; arr4 = [ "all" "strings" "are the same" "type" ]; arr5 = [ [ 1 2 ] [ "a" "b" "c" ] ]; arr7 = [ 1 2 3 ]; arr8 = [ 1 2 ]; bare-key = "value"; bare_key = "value"; bin1 = 214; bool1 = true; bool2 = false; "character encoding" = "value"; d = { e = { f = { }; }; }; dog = { "tater.man" = { type = { name = "pug"; }; }; }; flt1 = 1; flt2 = 3.1415; flt3 = -0.01; flt4 = 5e+22; flt5 = 1e+06; flt6 = -0.02; flt7 = 6.626e-34; flt8 = 9.22462e+06; g = { h = { i = { }; }; }; hex1 = 3735928559; hex2 = 3735928559; hex3 = 3735928559; int1 = 99; int2 = 42; int3 = 0; int4 = -17; int5 = 1000; int6 = 5349221; int7 = 12345; j = { "ʞ" = { l = { }; }; }; key = "value"; key2 = "value"; name = "Orange"; oct1 = 342391; oct2 = 493; physical = { color = "orange"; shape = "round"; }; products = [ { name = "Hammer"; sku = 738594937; } { } { color = "gray"; name = "Nail"; sku = 284758393; } ]; "quoted \"value\"" = "value"; site = { "google.com" = true; }; str = "I'm a string. \"You can quote me\". Name\tJosé\nLocation\tSF."; table-1 = { key1 = "some string"; key2 = 123; }; table-2 = { key1 = "another string"; key2 = 456; }; x = { y = { z = { w = { animal = { type = { name = "pug"; }; }; name = { first = "Tom"; last = "Preston-Werner"; }; point = { x = 1; y = 2; }; }; }; }; }; "ʎǝʞ" = "value"; } { metadata = { "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"; "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"; "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"; "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"; }; package = [ { dependencies = [ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" ]; name = "aho-corasick"; source = "registry+https://github.com/rust-lang/crates.io-index"; version = "0.6.4"; } { name = "ansi_term"; source = "registry+https://github.com/rust-lang/crates.io-index"; version = "0.9.0"; } { dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" ]; name = "atty"; source = "registry+https://github.com/rust-lang/crates.io-index"; version = "0.2.10"; } ]; } ]
|
||||||
|
|
|
@ -46,15 +46,15 @@
|
||||||
"character encoding" = "value"
|
"character encoding" = "value"
|
||||||
"ʎǝʞ" = "value"
|
"ʎǝʞ" = "value"
|
||||||
'key2' = "value"
|
'key2' = "value"
|
||||||
#'quoted "value"' = "value"
|
'quoted "value"' = "value"
|
||||||
|
|
||||||
name = "Orange"
|
name = "Orange"
|
||||||
|
|
||||||
# FIXME: cpptoml doesn't handle dotted keys properly yet.
|
physical.color = "orange"
|
||||||
#physical.color = "orange"
|
physical.shape = "round"
|
||||||
#physical.shape = "round"
|
site."google.com" = true
|
||||||
#site."google.com" = true
|
|
||||||
|
|
||||||
|
# This is legal according to the spec, but cpptoml doesn't handle it.
|
||||||
#a.b.c = 1
|
#a.b.c = 1
|
||||||
#a.d = 2
|
#a.d = 2
|
||||||
|
|
||||||
|
@ -68,16 +68,14 @@
|
||||||
int6 = 5_349_221
|
int6 = 5_349_221
|
||||||
int7 = 1_2_3_4_5
|
int7 = 1_2_3_4_5
|
||||||
|
|
||||||
# FIXME: cpptoml doesn't support these yet:
|
hex1 = 0xDEADBEEF
|
||||||
|
hex2 = 0xdeadbeef
|
||||||
|
hex3 = 0xdead_beef
|
||||||
|
|
||||||
#hex1 = 0xDEADBEEF
|
oct1 = 0o01234567
|
||||||
#hex2 = 0xdeadbeef
|
oct2 = 0o755
|
||||||
#hex3 = 0xdead_beef
|
|
||||||
|
|
||||||
#oct1 = 0o01234567
|
bin1 = 0b11010110
|
||||||
#oct2 = 0o755
|
|
||||||
|
|
||||||
#bin1 = 0b11010110
|
|
||||||
|
|
||||||
flt1 = +1.0
|
flt1 = +1.0
|
||||||
flt2 = 3.1415
|
flt2 = 3.1415
|
||||||
|
@ -126,8 +124,8 @@
|
||||||
key1 = "another string"
|
key1 = "another string"
|
||||||
key2 = 456
|
key2 = 456
|
||||||
|
|
||||||
#[dog."tater.man"]
|
[dog."tater.man"]
|
||||||
#type.name = "pug"
|
type.name = "pug"
|
||||||
|
|
||||||
[a.b.c]
|
[a.b.c]
|
||||||
[ d.e.f ]
|
[ d.e.f ]
|
||||||
|
@ -137,7 +135,7 @@
|
||||||
|
|
||||||
name = { first = "Tom", last = "Preston-Werner" }
|
name = { first = "Tom", last = "Preston-Werner" }
|
||||||
point = { x = 1, y = 2 }
|
point = { x = 1, y = 2 }
|
||||||
#animal = { type.name = "pug" }
|
animal = { type.name = "pug" }
|
||||||
|
|
||||||
[[products]]
|
[[products]]
|
||||||
name = "Hammer"
|
name = "Hammer"
|
||||||
|
|
4
tests/lang/parse-fail-mixed-nested-attrs1.nix
Normal file
4
tests/lang/parse-fail-mixed-nested-attrs1.nix
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
x.z = 3;
|
||||||
|
x = { y = 3; z = 3; };
|
||||||
|
}
|
4
tests/lang/parse-fail-mixed-nested-attrs2.nix
Normal file
4
tests/lang/parse-fail-mixed-nested-attrs2.nix
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
x.y.y = 3;
|
||||||
|
x = { y.y= 3; z = 3; };
|
||||||
|
}
|
4
tests/lang/parse-okay-mixed-nested-attrs-1.nix
Normal file
4
tests/lang/parse-okay-mixed-nested-attrs-1.nix
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
x = { y = 3; z = 3; };
|
||||||
|
x.q = 3;
|
||||||
|
}
|
4
tests/lang/parse-okay-mixed-nested-attrs-2.nix
Normal file
4
tests/lang/parse-okay-mixed-nested-attrs-2.nix
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
x.q = 3;
|
||||||
|
x = { y = 3; z = 3; };
|
||||||
|
}
|
7
tests/lang/parse-okay-mixed-nested-attrs-3.nix
Normal file
7
tests/lang/parse-okay-mixed-nested-attrs-3.nix
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
services.ssh.enable = true;
|
||||||
|
services.ssh = { port = 123; };
|
||||||
|
services = {
|
||||||
|
httpd.enable = true;
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue