Merge remote-tracking branch 'origin/master' into flakes

This commit is contained in:
Eelco Dolstra 2019-05-29 12:36:44 +02:00
commit 6636808e90
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
16 changed files with 486 additions and 214 deletions

View file

@ -14,7 +14,8 @@
<varlistentry><term><envar>IN_NIX_SHELL</envar></term>
<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>

View file

@ -217,7 +217,25 @@ but can also be written as:
ellipsis(<literal>...</literal>) as you can access attribute names as
<literal>a</literal>, using <literal>args.a</literal>, which was given as an
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>

View file

@ -2,12 +2,6 @@
if [ -n "${__ETC_PROFILE_NIX_SOURCED:-}" ]; then return; fi
__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_PROFILES="@localstatedir@/nix/profiles/default $HOME/.nix-profile"

View file

@ -57,7 +57,7 @@ if [ -n "$HOME" ] && [ -n "$USER" ]; then
# Set up environment.
# 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.
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
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

View file

@ -2,7 +2,7 @@
, 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; };

View file

@ -4,8 +4,8 @@
* @date May 2013
*/
#ifndef _CPPTOML_H_
#define _CPPTOML_H_
#ifndef CPPTOML_H
#define CPPTOML_H
#include <algorithm>
#include <cassert>
@ -84,11 +84,12 @@ class option
return &value_;
}
const T& value_or(const T& alternative) const
template <class U>
T value_or(U&& alternative) const
{
if (!empty_)
return value_;
return alternative;
return static_cast<T>(std::forward<U>(alternative));
}
private:
@ -295,13 +296,12 @@ struct valid_value_or_string_convertible
};
template <class T>
struct value_traits<T, typename std::
enable_if<valid_value_or_string_convertible<T>::
value>::type>
struct value_traits<T, typename std::enable_if<
valid_value_or_string_convertible<T>::value>::type>
{
using value_type = typename std::
conditional<valid_value<typename std::decay<T>::type>::value,
typename std::decay<T>::type, std::string>::type;
using value_type = typename std::conditional<
valid_value<typename std::decay<T>::type>::value,
typename std::decay<T>::type, std::string>::type;
using type = value<value_type>;
@ -312,12 +312,11 @@ struct value_traits<T, typename std::
};
template <class T>
struct value_traits<T,
typename std::
enable_if<!valid_value_or_string_convertible<T>::value
&& std::is_floating_point<
typename std::decay<T>::type>::value>::
type>
struct value_traits<
T,
typename std::enable_if<
!valid_value_or_string_convertible<T>::value
&& std::is_floating_point<typename std::decay<T>::type>::value>::type>
{
using value_type = typename std::decay<T>::type;
@ -330,11 +329,11 @@ struct value_traits<T,
};
template <class T>
struct value_traits<T,
typename std::
enable_if<!valid_value_or_string_convertible<T>::value
&& std::is_signed<typename std::decay<T>::
type>::value>::type>
struct value_traits<
T, typename std::enable_if<
!valid_value_or_string_convertible<T>::value
&& !std::is_floating_point<typename std::decay<T>::type>::value
&& std::is_signed<typename std::decay<T>::type>::value>::type>
{
using value_type = int64_t;
@ -356,11 +355,10 @@ struct value_traits<T,
};
template <class T>
struct value_traits<T,
typename std::
enable_if<!valid_value_or_string_convertible<T>::value
&& std::is_unsigned<typename std::decay<T>::
type>::value>::type>
struct value_traits<
T, typename std::enable_if<
!valid_value_or_string_convertible<T>::value
&& std::is_unsigned<typename std::decay<T>::type>::value>::type>
{
using value_type = int64_t;
@ -395,10 +393,15 @@ struct array_of_trait<array>
template <class T>
inline std::shared_ptr<typename value_traits<T>::type> make_value(T&& val);
inline std::shared_ptr<array> make_array();
namespace detail
{
template <class T>
inline std::shared_ptr<T> make_element();
}
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)
/// 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)
base_type type() const
{
return type_;
return type_;
}
protected:
@ -698,7 +701,7 @@ inline std::shared_ptr<value<double>> base::as()
if (type() == base_type::INT)
{
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
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 (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)
{
@ -1027,11 +1031,14 @@ inline std::shared_ptr<array> make_array()
return std::make_shared<make_shared_enabler>();
}
namespace detail
{
template <>
inline std::shared_ptr<array> make_element<array>()
{
return make_array();
}
} // namespace detail
/**
* Obtains a option<vector<T>>. The option will be empty if the array
@ -1060,7 +1067,7 @@ class table;
class table_array : public base
{
friend class table;
friend std::shared_ptr<table_array> make_table_array();
friend std::shared_ptr<table_array> make_table_array(bool);
public:
std::shared_ptr<base> clone() const override;
@ -1152,14 +1159,25 @@ class table_array : public base
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:
#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
}
#else
table_array()
table_array(bool is_inline = false) : is_inline_(is_inline)
{
// nothing
}
@ -1169,26 +1187,30 @@ class table_array : public base
table_array& operator=(const table_array& rhs) = delete;
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
{
make_shared_enabler()
make_shared_enabler(bool mse_is_inline) : table_array(mse_is_inline)
{
// nothing
}
};
return std::make_shared<make_shared_enabler>();
return std::make_shared<make_shared_enabler>(is_inline);
}
namespace detail
{
template <>
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
// 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>();
}
namespace detail
{
template <>
inline std::shared_ptr<table> make_element<table>()
{
return make_table();
}
} // namespace detail
template <class T>
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
{
auto result = make_table_array();
auto result = make_table_array(is_inline());
result->reserve(array_.size());
for (const auto& ptr : array_)
result->array_.push_back(ptr->clone()->as_table());
@ -1738,6 +1763,11 @@ inline bool is_number(char c)
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.
*/
@ -1766,6 +1796,13 @@ class consumer
[&](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 val = 0;
@ -1830,7 +1867,7 @@ inline std::istream& getline(std::istream& input, std::string& line)
line.push_back(static_cast<char>(c));
}
}
}
} // namespace detail
/**
* The parser class.
@ -1914,21 +1951,25 @@ class parser
std::string full_table_name;
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())
throw_parse_exception("Empty component of table name");
if (!full_table_name.empty())
full_table_name += ".";
full_table_name += '.';
full_table_name += part;
if (curr_table->contains(part))
{
#if !defined(__PGI)
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())
curr_table = static_cast<table*>(b.get());
else if (b->is_table_array())
@ -1946,16 +1987,23 @@ class parser
curr_table->insert(part, make_table());
curr_table = static_cast<table*>(curr_table->get(part).get());
}
consume_whitespace(it, end);
if (it != end && *it == '.')
++it;
consume_whitespace(it, end);
}
};
key_part_handler(parse_key(it, end, key_end, key_part_handler));
if (it == end)
throw_parse_exception(
"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
if (!inserted)
{
@ -1969,8 +2017,9 @@ class parser
// since it has already been defined. If there aren't any
// values, then it was implicitly created by something like
// [a.b]
if (curr_table->empty() || std::any_of(curr_table->begin(),
curr_table->end(), is_value))
if (curr_table->empty()
|| std::any_of(curr_table->begin(), curr_table->end(),
is_value))
{
throw_parse_exception("Redefinition of table "
+ full_table_name);
@ -1989,36 +2038,45 @@ class parser
if (it == end || *it == ']')
throw_parse_exception("Table array name cannot be empty");
std::string full_ta_name;
while (it != end && *it != ']')
{
auto part = parse_key(it, end,
[](char c) { return c == '.' || c == ']'; });
auto key_end = [](char c) { return c == ']'; };
std::string full_ta_name;
auto key_part_handler = [&](const std::string& part) {
if (part.empty())
throw_parse_exception("Empty component of table array name");
if (!full_ta_name.empty())
full_ta_name += ".";
full_ta_name += '.';
full_ta_name += part;
consume_whitespace(it, end);
if (it != end && *it == '.')
++it;
consume_whitespace(it, end);
if (curr_table->contains(part))
{
#if !defined(__PGI)
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
// 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 (!b->is_table_array())
{
throw_parse_exception("Key " + full_ta_name
+ " is not a 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());
curr_table = v->get().back().get();
}
@ -2059,15 +2117,16 @@ class parser
= static_cast<table*>(curr_table->get(part).get());
}
}
}
};
key_part_handler(parse_key(it, end, key_end, key_part_handler));
// consume the last "]]"
if (it == end)
auto eat = make_consumer(it, end, [this]() {
throw_parse_exception("Unterminated table array name");
++it;
if (it == end)
throw_parse_exception("Unterminated table array name");
++it;
});
eat(']');
eat(']');
consume_whitespace(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,
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))
throw_parse_exception("Key " + key + " already present");
if (it == end || *it != '=')
@ -2087,18 +2174,57 @@ class parser
consume_whitespace(it, end);
}
template <class Function>
std::string parse_key(std::string::iterator& it,
const std::string::iterator& end, Function&& fun)
template <class KeyEndFinder, class KeyPartHandler>
std::string
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);
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
{
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);
}
}
@ -2142,12 +2268,6 @@ class parser
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
{
STRING = 1,
@ -2193,7 +2313,7 @@ class parser
parse_type determine_value_type(const std::string::iterator& it,
const std::string::iterator& end)
{
if(it == end)
if (it == end)
{
throw_parse_exception("Failed to parse value type");
}
@ -2209,7 +2329,11 @@ class parser
{
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);
}
@ -2235,6 +2359,13 @@ class parser
auto check_it = it;
if (*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))
++check_it;
if (check_it != end && *check_it == '.')
@ -2283,57 +2414,56 @@ class parser
bool consuming = false;
std::shared_ptr<value<std::string>> ret;
auto handle_line
= [&](std::string::iterator& local_it,
std::string::iterator& local_end) {
if (consuming)
{
local_it = std::find_if_not(local_it, local_end, is_ws);
auto handle_line = [&](std::string::iterator& local_it,
std::string::iterator& local_end) {
if (consuming)
{
local_it = std::find_if_not(local_it, local_end, is_ws);
// whole line is whitespace
if (local_it == local_end)
return;
}
// whole line is whitespace
if (local_it == local_end)
return;
}
consuming = false;
consuming = false;
while (local_it != local_end)
{
// handle escaped characters
if (delim == '"' && *local_it == '\\')
{
auto check = local_it;
// check if this is an actual escape sequence or a
// whitespace escaping backslash
++check;
consume_whitespace(check, local_end);
if (check == local_end)
{
consuming = true;
break;
}
while (local_it != local_end)
{
// handle escaped characters
if (delim == '"' && *local_it == '\\')
{
auto check = local_it;
// check if this is an actual escape sequence or a
// whitespace escaping backslash
++check;
consume_whitespace(check, local_end);
if (check == local_end)
{
consuming = true;
break;
}
ss << parse_escape_code(local_it, local_end);
continue;
}
ss << parse_escape_code(local_it, local_end);
continue;
}
// if we can end the string
if (std::distance(local_it, local_end) >= 3)
{
auto check = local_it;
// check for """
if (*check++ == delim && *check++ == delim
&& *check++ == delim)
{
local_it = check;
ret = make_value<std::string>(ss.str());
break;
}
}
// if we can end the string
if (std::distance(local_it, local_end) >= 3)
{
auto check = local_it;
// check for """
if (*check++ == delim && *check++ == delim
&& *check++ == delim)
{
local_it = check;
ret = make_value<std::string>(ss.str());
break;
}
}
ss << *local_it++;
}
};
ss << *local_it++;
}
};
// handle the remainder of the current line
handle_line(it, end);
@ -2514,17 +2644,13 @@ class parser
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)
{
if (is_number(c))
return static_cast<uint32_t>(c - '0');
return 10 + static_cast<uint32_t>(
c - ((c >= 'a' && c <= 'f') ? 'a' : 'A'));
return 10
+ static_cast<uint32_t>(c
- ((c >= 'a' && c <= 'f') ? 'a' : 'A'));
}
std::shared_ptr<base> parse_number(std::string::iterator& it,
@ -2538,25 +2664,6 @@ class parser
++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 = [&]() {
if (check_it != end && *check_it == '0' && check_it + 1 != check_end
&& 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();
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();
if (check_it != end
@ -2604,14 +2784,17 @@ class parser
}
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};
v = prefix + v;
v.erase(std::remove(v.begin(), v.end(), '_'), v.end());
it = end;
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)
{
@ -2674,18 +2857,33 @@ class parser
std::string::iterator find_end_of_number(std::string::iterator it,
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'
&& 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 end)
{
return std::find_if(it, end, [](char c) {
return !is_number(c) && c != 'T' && c != 'Z' && c != ':' && c != '-'
&& c != '+' && c != '.';
auto end_of_date = std::find_if(it, end, [](char c) {
return !is_number(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)
return make_value(ldate);
eat('T');
eat.eat_or('T', ' ');
local_datetime ldt;
static_cast<local_date&>(ldt) = ldate;
@ -2850,9 +3048,9 @@ class parser
auto arr = make_array();
while (it != end && *it != ']')
{
auto value = parse_value(it, end);
if (auto v = value->as<Value>())
arr->get().push_back(value);
auto val = parse_value(it, end);
if (auto v = val->as<Value>())
arr->get().push_back(val);
else
throw_parse_exception("Arrays must be homogeneous");
skip_whitespace_and_comments(it, end);
@ -2871,7 +3069,7 @@ class parser
std::string::iterator& it,
std::string::iterator& end)
{
auto arr = make_element<Object>();
auto arr = detail::make_element<Object>();
while (it != end && *it != ']')
{
@ -2881,7 +3079,7 @@ class parser
arr->get().push_back(((*this).*fun)(it, end));
skip_whitespace_and_comments(it, end);
if (*it != ',')
if (it == end || *it != ',')
break;
++it;
@ -2906,8 +3104,11 @@ class parser
throw_parse_exception("Unterminated inline table");
consume_whitespace(it, end);
parse_key_value(it, end, tbl.get());
consume_whitespace(it, end);
if (it != end && *it != '}')
{
parse_key_value(it, end, tbl.get());
consume_whitespace(it, end);
}
} while (*it == ',');
if (it == end || *it != '}')
@ -2987,7 +3188,8 @@ class parser
if (it[4] != '-' || it[7] != '-')
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
auto time_end = find_end_of_time(it + 11, date_end);
@ -3243,7 +3445,7 @@ class toml_writer
{
res += "\\\\";
}
else if ((const uint32_t)*it <= 0x001f)
else if (static_cast<uint32_t>(*it) <= UINT32_C(0x001f))
{
res += "\\u";
std::stringstream ss;
@ -3274,12 +3476,21 @@ class toml_writer
*/
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;
write(v.get());
auto double_str = ss.str();
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.
*/
template <class T>
typename std::enable_if<is_one_of<T, int64_t, local_date, local_time,
local_datetime,
offset_datetime>::value>::type
typename std::enable_if<
is_one_of<T, int64_t, local_date, local_time, local_datetime,
offset_datetime>::value>::type
write(const value<T>& v)
{
write(v.get());
@ -3453,5 +3664,5 @@ inline std::ostream& operator<<(std::ostream& stream, const array& a)
a.accept(writer);
return stream;
}
}
#endif
} // namespace cpptoml
#endif // CPPTOML_H

View file

@ -81,6 +81,8 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
AttrPath::iterator i;
// All attrpaths have at least one attr
assert(!attrPath.empty());
// Checking attrPath validity.
// ===========================
for (i = attrPath.begin(); i + 1 < attrPath.end(); i++) {
if (i->symbol.set()) {
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
@ -102,11 +104,29 @@ static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
attrs = nested;
}
}
// Expr insertion.
// ==========================
if (i->symbol.set()) {
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
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 {
// This attr path is not defined. Let's create it.
attrs->attrs[i->symbol] = ExprAttrs::AttrDef(e, pos);
e->setName(i->symbol);
}

View file

@ -352,11 +352,18 @@ public:
if (running || done || expected || failed) {
if (running)
s = fmt(ANSI_BLUE + numberFmt + ANSI_NORMAL "/" ANSI_GREEN + numberFmt + ANSI_NORMAL "/" + numberFmt,
running / unit, done / unit, expected / unit);
if (expected != 0)
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)
s = fmt(ANSI_GREEN + numberFmt + ANSI_NORMAL "/" + numberFmt,
done / unit, expected / unit);
if (expected != 0)
s = fmt(ANSI_GREEN + numberFmt + ANSI_NORMAL "/" + numberFmt,
done / unit, expected / unit);
else
s = fmt(ANSI_GREEN + numberFmt + ANSI_NORMAL, done / unit);
else
s = fmt(done ? ANSI_GREEN + numberFmt + ANSI_NORMAL : numberFmt, done / unit);
s = fmt(itemFmt, s);

View file

@ -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"; } ]; } ]

View file

@ -46,15 +46,15 @@
"character encoding" = "value"
"ʎǝʞ" = "value"
'key2' = "value"
#'quoted "value"' = "value"
'quoted "value"' = "value"
name = "Orange"
# FIXME: cpptoml doesn't handle dotted keys properly yet.
#physical.color = "orange"
#physical.shape = "round"
#site."google.com" = true
physical.color = "orange"
physical.shape = "round"
site."google.com" = true
# This is legal according to the spec, but cpptoml doesn't handle it.
#a.b.c = 1
#a.d = 2
@ -68,16 +68,14 @@
int6 = 5_349_221
int7 = 1_2_3_4_5
# FIXME: cpptoml doesn't support these yet:
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
hex3 = 0xdead_beef
#hex1 = 0xDEADBEEF
#hex2 = 0xdeadbeef
#hex3 = 0xdead_beef
oct1 = 0o01234567
oct2 = 0o755
#oct1 = 0o01234567
#oct2 = 0o755
#bin1 = 0b11010110
bin1 = 0b11010110
flt1 = +1.0
flt2 = 3.1415
@ -126,8 +124,8 @@
key1 = "another string"
key2 = 456
#[dog."tater.man"]
#type.name = "pug"
[dog."tater.man"]
type.name = "pug"
[a.b.c]
[ d.e.f ]
@ -137,7 +135,7 @@
name = { first = "Tom", last = "Preston-Werner" }
point = { x = 1, y = 2 }
#animal = { type.name = "pug" }
animal = { type.name = "pug" }
[[products]]
name = "Hammer"

View file

@ -0,0 +1,4 @@
{
x.z = 3;
x = { y = 3; z = 3; };
}

View file

@ -0,0 +1,4 @@
{
x.y.y = 3;
x = { y.y= 3; z = 3; };
}

View file

@ -0,0 +1,4 @@
{
x = { y = 3; z = 3; };
x.q = 3;
}

View file

@ -0,0 +1,4 @@
{
x.q = 3;
x = { y = 3; z = 3; };
}

View file

@ -0,0 +1,7 @@
{
services.ssh.enable = true;
services.ssh = { port = 123; };
services = {
httpd.enable = true;
};
}