Mixed type arrays (#358)
* Added support of mixed-type arrays * Add tests cases * Replaced &'static str type for type_ and created a new enum instead * Restored ArrayMixedType
This commit is contained in:
parent
3e9f8cbd83
commit
c822128a02
19
src/de.rs
19
src/de.rs
|
@ -11,7 +11,6 @@ use std::f64;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem::discriminant;
|
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::vec;
|
use std::vec;
|
||||||
|
|
||||||
|
@ -147,10 +146,6 @@ enum ErrorKind {
|
||||||
found: &'static str,
|
found: &'static str,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// An array was decoded but the types inside of it were mixed, which is
|
|
||||||
/// disallowed by TOML.
|
|
||||||
MixedArrayType,
|
|
||||||
|
|
||||||
/// A duplicate table definition was found.
|
/// A duplicate table definition was found.
|
||||||
DuplicateTable(String),
|
DuplicateTable(String),
|
||||||
|
|
||||||
|
@ -1827,13 +1822,7 @@ impl<'a> Deserializer<'a> {
|
||||||
if let Some(span) = self.eat_spanned(Token::RightBracket)? {
|
if let Some(span) = self.eat_spanned(Token::RightBracket)? {
|
||||||
return Ok((span, ret));
|
return Ok((span, ret));
|
||||||
}
|
}
|
||||||
let at = self.tokens.current();
|
|
||||||
let value = self.value()?;
|
let value = self.value()?;
|
||||||
if let Some(last) = ret.last() {
|
|
||||||
if !value.same_type(last) {
|
|
||||||
return Err(self.error(at, ErrorKind::MixedArrayType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret.push(value);
|
ret.push(value);
|
||||||
intermediate(self)?;
|
intermediate(self)?;
|
||||||
if !self.eat(Token::Comma)? {
|
if !self.eat(Token::Comma)? {
|
||||||
|
@ -2118,7 +2107,6 @@ impl fmt::Display for Error {
|
||||||
}
|
}
|
||||||
ErrorKind::NumberInvalid => "invalid number".fmt(f)?,
|
ErrorKind::NumberInvalid => "invalid number".fmt(f)?,
|
||||||
ErrorKind::DateInvalid => "invalid date".fmt(f)?,
|
ErrorKind::DateInvalid => "invalid date".fmt(f)?,
|
||||||
ErrorKind::MixedArrayType => "mixed types in an array".fmt(f)?,
|
|
||||||
ErrorKind::DuplicateTable(ref s) => {
|
ErrorKind::DuplicateTable(ref s) => {
|
||||||
write!(f, "redefinition of table `{}`", s)?;
|
write!(f, "redefinition of table `{}`", s)?;
|
||||||
}
|
}
|
||||||
|
@ -2180,7 +2168,6 @@ impl error::Error for Error {
|
||||||
ErrorKind::Wanted { .. } => "expected a token but found another",
|
ErrorKind::Wanted { .. } => "expected a token but found another",
|
||||||
ErrorKind::NumberInvalid => "invalid number",
|
ErrorKind::NumberInvalid => "invalid number",
|
||||||
ErrorKind::DateInvalid => "invalid date",
|
ErrorKind::DateInvalid => "invalid date",
|
||||||
ErrorKind::MixedArrayType => "mixed types in an array",
|
|
||||||
ErrorKind::DuplicateTable(_) => "duplicate table",
|
ErrorKind::DuplicateTable(_) => "duplicate table",
|
||||||
ErrorKind::RedefineAsArray => "table redefined as array",
|
ErrorKind::RedefineAsArray => "table redefined as array",
|
||||||
ErrorKind::EmptyTableKey => "empty table key found",
|
ErrorKind::EmptyTableKey => "empty table key found",
|
||||||
|
@ -2283,9 +2270,3 @@ impl<'a> E<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Value<'a> {
|
|
||||||
fn same_type(&self, other: &Value<'a>) -> bool {
|
|
||||||
discriminant(&self.e) == discriminant(&other.e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
68
src/ser.rs
68
src/ser.rs
|
@ -124,8 +124,8 @@ pub enum Error {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
KeyNewline,
|
KeyNewline,
|
||||||
|
|
||||||
/// Arrays in TOML must have a homogenous type, but a heterogeneous array
|
/// An array had to be homogenous, but now it is allowed to be heterogenous.
|
||||||
/// was emitted.
|
#[doc(hidden)]
|
||||||
ArrayMixedType,
|
ArrayMixedType,
|
||||||
|
|
||||||
/// All values in a TOML table must be emitted before further tables are
|
/// All values in a TOML table must be emitted before further tables are
|
||||||
|
@ -201,6 +201,12 @@ pub struct Serializer<'a> {
|
||||||
settings: Rc<Settings>,
|
settings: Rc<Settings>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
enum ArrayState {
|
||||||
|
Started,
|
||||||
|
StartedAsATable,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum State<'a> {
|
enum State<'a> {
|
||||||
Table {
|
Table {
|
||||||
|
@ -212,7 +218,7 @@ enum State<'a> {
|
||||||
Array {
|
Array {
|
||||||
parent: &'a State<'a>,
|
parent: &'a State<'a>,
|
||||||
first: &'a Cell<bool>,
|
first: &'a Cell<bool>,
|
||||||
type_: &'a Cell<Option<&'static str>>,
|
type_: &'a Cell<Option<ArrayState>>,
|
||||||
len: Option<usize>,
|
len: Option<usize>,
|
||||||
},
|
},
|
||||||
End,
|
End,
|
||||||
|
@ -222,7 +228,7 @@ enum State<'a> {
|
||||||
pub struct SerializeSeq<'a, 'b> {
|
pub struct SerializeSeq<'a, 'b> {
|
||||||
ser: &'b mut Serializer<'a>,
|
ser: &'b mut Serializer<'a>,
|
||||||
first: Cell<bool>,
|
first: Cell<bool>,
|
||||||
type_: Cell<Option<&'static str>>,
|
type_: Cell<Option<ArrayState>>,
|
||||||
len: Option<usize>,
|
len: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,7 +423,7 @@ impl<'a> Serializer<'a> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display<T: fmt::Display>(&mut self, t: T, type_: &'static str) -> Result<(), Error> {
|
fn display<T: fmt::Display>(&mut self, t: T, type_: ArrayState) -> Result<(), Error> {
|
||||||
self.emit_key(type_)?;
|
self.emit_key(type_)?;
|
||||||
write!(self.dst, "{}", t).map_err(ser::Error::custom)?;
|
write!(self.dst, "{}", t).map_err(ser::Error::custom)?;
|
||||||
if let State::Table { .. } = self.state {
|
if let State::Table { .. } = self.state {
|
||||||
|
@ -426,7 +432,7 @@ impl<'a> Serializer<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_key(&mut self, type_: &'static str) -> Result<(), Error> {
|
fn emit_key(&mut self, type_: ArrayState) -> Result<(), Error> {
|
||||||
self.array_type(type_)?;
|
self.array_type(type_)?;
|
||||||
let state = self.state.clone();
|
let state = self.state.clone();
|
||||||
self._emit_key(&state)
|
self._emit_key(&state)
|
||||||
|
@ -491,16 +497,12 @@ impl<'a> Serializer<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn array_type(&mut self, type_: &'static str) -> Result<(), Error> {
|
fn array_type(&mut self, type_: ArrayState) -> Result<(), Error> {
|
||||||
let prev = match self.state {
|
let prev = match self.state {
|
||||||
State::Array { type_, .. } => type_,
|
State::Array { type_, .. } => type_,
|
||||||
_ => return Ok(()),
|
_ => return Ok(()),
|
||||||
};
|
};
|
||||||
if let Some(prev) = prev.get() {
|
if let None = prev.get() {
|
||||||
if prev != type_ {
|
|
||||||
return Err(Error::ArrayMixedType);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
prev.set(Some(type_));
|
prev.set(Some(type_));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -747,7 +749,7 @@ impl<'a> Serializer<'a> {
|
||||||
|
|
||||||
macro_rules! serialize_float {
|
macro_rules! serialize_float {
|
||||||
($this:expr, $v:expr) => {{
|
($this:expr, $v:expr) => {{
|
||||||
$this.emit_key("float")?;
|
$this.emit_key(ArrayState::Started)?;
|
||||||
if ($v.is_nan() || $v == 0.0) && $v.is_sign_negative() {
|
if ($v.is_nan() || $v == 0.0) && $v.is_sign_negative() {
|
||||||
write!($this.dst, "-").map_err(ser::Error::custom)?;
|
write!($this.dst, "-").map_err(ser::Error::custom)?;
|
||||||
}
|
}
|
||||||
|
@ -778,39 +780,39 @@ impl<'a, 'b> ser::Serializer for &'b mut Serializer<'a> {
|
||||||
type SerializeStructVariant = ser::Impossible<(), Error>;
|
type SerializeStructVariant = ser::Impossible<(), Error>;
|
||||||
|
|
||||||
fn serialize_bool(self, v: bool) -> Result<(), Self::Error> {
|
fn serialize_bool(self, v: bool) -> Result<(), Self::Error> {
|
||||||
self.display(v, "bool")
|
self.display(v, ArrayState::Started)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_i8(self, v: i8) -> Result<(), Self::Error> {
|
fn serialize_i8(self, v: i8) -> Result<(), Self::Error> {
|
||||||
self.display(v, "integer")
|
self.display(v, ArrayState::Started)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_i16(self, v: i16) -> Result<(), Self::Error> {
|
fn serialize_i16(self, v: i16) -> Result<(), Self::Error> {
|
||||||
self.display(v, "integer")
|
self.display(v, ArrayState::Started)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_i32(self, v: i32) -> Result<(), Self::Error> {
|
fn serialize_i32(self, v: i32) -> Result<(), Self::Error> {
|
||||||
self.display(v, "integer")
|
self.display(v, ArrayState::Started)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_i64(self, v: i64) -> Result<(), Self::Error> {
|
fn serialize_i64(self, v: i64) -> Result<(), Self::Error> {
|
||||||
self.display(v, "integer")
|
self.display(v, ArrayState::Started)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_u8(self, v: u8) -> Result<(), Self::Error> {
|
fn serialize_u8(self, v: u8) -> Result<(), Self::Error> {
|
||||||
self.display(v, "integer")
|
self.display(v, ArrayState::Started)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_u16(self, v: u16) -> Result<(), Self::Error> {
|
fn serialize_u16(self, v: u16) -> Result<(), Self::Error> {
|
||||||
self.display(v, "integer")
|
self.display(v, ArrayState::Started)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_u32(self, v: u32) -> Result<(), Self::Error> {
|
fn serialize_u32(self, v: u32) -> Result<(), Self::Error> {
|
||||||
self.display(v, "integer")
|
self.display(v, ArrayState::Started)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_u64(self, v: u64) -> Result<(), Self::Error> {
|
fn serialize_u64(self, v: u64) -> Result<(), Self::Error> {
|
||||||
self.display(v, "integer")
|
self.display(v, ArrayState::Started)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_f32(self, v: f32) -> Result<(), Self::Error> {
|
fn serialize_f32(self, v: f32) -> Result<(), Self::Error> {
|
||||||
|
@ -827,7 +829,7 @@ impl<'a, 'b> ser::Serializer for &'b mut Serializer<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_str(self, value: &str) -> Result<(), Self::Error> {
|
fn serialize_str(self, value: &str) -> Result<(), Self::Error> {
|
||||||
self.emit_key("string")?;
|
self.emit_key(ArrayState::Started)?;
|
||||||
self.emit_str(value, false)?;
|
self.emit_str(value, false)?;
|
||||||
if let State::Table { .. } = self.state {
|
if let State::Table { .. } = self.state {
|
||||||
self.dst.push_str("\n");
|
self.dst.push_str("\n");
|
||||||
|
@ -893,7 +895,7 @@ impl<'a, 'b> ser::Serializer for &'b mut Serializer<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||||
self.array_type("array")?;
|
self.array_type(ArrayState::Started)?;
|
||||||
Ok(SerializeSeq {
|
Ok(SerializeSeq {
|
||||||
ser: self,
|
ser: self,
|
||||||
first: Cell::new(true),
|
first: Cell::new(true),
|
||||||
|
@ -925,7 +927,7 @@ impl<'a, 'b> ser::Serializer for &'b mut Serializer<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||||
self.array_type("table")?;
|
self.array_type(ArrayState::StartedAsATable)?;
|
||||||
Ok(SerializeTable::Table {
|
Ok(SerializeTable::Table {
|
||||||
ser: self,
|
ser: self,
|
||||||
key: String::new(),
|
key: String::new(),
|
||||||
|
@ -940,10 +942,10 @@ impl<'a, 'b> ser::Serializer for &'b mut Serializer<'a> {
|
||||||
_len: usize,
|
_len: usize,
|
||||||
) -> Result<Self::SerializeStruct, Self::Error> {
|
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||||
if name == datetime::NAME {
|
if name == datetime::NAME {
|
||||||
self.array_type("datetime")?;
|
self.array_type(ArrayState::Started)?;
|
||||||
Ok(SerializeTable::Datetime(self))
|
Ok(SerializeTable::Datetime(self))
|
||||||
} else {
|
} else {
|
||||||
self.array_type("table")?;
|
self.array_type(ArrayState::StartedAsATable)?;
|
||||||
Ok(SerializeTable::Table {
|
Ok(SerializeTable::Table {
|
||||||
ser: self,
|
ser: self,
|
||||||
key: String::new(),
|
key: String::new(),
|
||||||
|
@ -988,8 +990,8 @@ impl<'a, 'b> ser::SerializeSeq for SerializeSeq<'a, 'b> {
|
||||||
|
|
||||||
fn end(self) -> Result<(), Error> {
|
fn end(self) -> Result<(), Error> {
|
||||||
match self.type_.get() {
|
match self.type_.get() {
|
||||||
Some("table") => return Ok(()),
|
Some(ArrayState::StartedAsATable) => return Ok(()),
|
||||||
Some(_) => match (self.len, &self.ser.settings.array) {
|
Some(ArrayState::Started) => match (self.len, &self.ser.settings.array) {
|
||||||
(Some(0..=1), _) | (_, &None) => {
|
(Some(0..=1), _) | (_, &None) => {
|
||||||
self.ser.dst.push_str("]");
|
self.ser.dst.push_str("]");
|
||||||
}
|
}
|
||||||
|
@ -1002,7 +1004,7 @@ impl<'a, 'b> ser::SerializeSeq for SerializeSeq<'a, 'b> {
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
assert!(self.first.get());
|
assert!(self.first.get());
|
||||||
self.ser.emit_key("array")?;
|
self.ser.emit_key(ArrayState::Started)?;
|
||||||
self.ser.dst.push_str("[]")
|
self.ser.dst.push_str("[]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1244,7 +1246,7 @@ impl<'a, 'b> ser::Serializer for DateStrEmitter<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_str(self, value: &str) -> Result<(), Self::Error> {
|
fn serialize_str(self, value: &str) -> Result<(), Self::Error> {
|
||||||
self.0.display(value, "datetime")?;
|
self.0.display(value, ArrayState::Started)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1528,13 +1530,13 @@ impl fmt::Display for Error {
|
||||||
match *self {
|
match *self {
|
||||||
Error::UnsupportedType => "unsupported Rust type".fmt(f),
|
Error::UnsupportedType => "unsupported Rust type".fmt(f),
|
||||||
Error::KeyNotString => "map key was not a string".fmt(f),
|
Error::KeyNotString => "map key was not a string".fmt(f),
|
||||||
Error::ArrayMixedType => "arrays cannot have mixed types".fmt(f),
|
|
||||||
Error::ValueAfterTable => "values must be emitted before tables".fmt(f),
|
Error::ValueAfterTable => "values must be emitted before tables".fmt(f),
|
||||||
Error::DateInvalid => "a serialized date was invalid".fmt(f),
|
Error::DateInvalid => "a serialized date was invalid".fmt(f),
|
||||||
Error::NumberInvalid => "a serialized number was invalid".fmt(f),
|
Error::NumberInvalid => "a serialized number was invalid".fmt(f),
|
||||||
Error::UnsupportedNone => "unsupported None value".fmt(f),
|
Error::UnsupportedNone => "unsupported None value".fmt(f),
|
||||||
Error::Custom(ref s) => s.fmt(f),
|
Error::Custom(ref s) => s.fmt(f),
|
||||||
Error::KeyNewline => unreachable!(),
|
Error::KeyNewline => unreachable!(),
|
||||||
|
Error::ArrayMixedType => unreachable!(),
|
||||||
Error::__Nonexhaustive => panic!(),
|
Error::__Nonexhaustive => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1545,13 +1547,13 @@ impl error::Error for Error {
|
||||||
match *self {
|
match *self {
|
||||||
Error::UnsupportedType => "unsupported Rust type",
|
Error::UnsupportedType => "unsupported Rust type",
|
||||||
Error::KeyNotString => "map key was not a string",
|
Error::KeyNotString => "map key was not a string",
|
||||||
Error::ArrayMixedType => "arrays cannot have mixed types",
|
|
||||||
Error::ValueAfterTable => "values must be emitted before tables",
|
Error::ValueAfterTable => "values must be emitted before tables",
|
||||||
Error::DateInvalid => "a serialized date was invalid",
|
Error::DateInvalid => "a serialized date was invalid",
|
||||||
Error::NumberInvalid => "a serialized number was invalid",
|
Error::NumberInvalid => "a serialized number was invalid",
|
||||||
Error::UnsupportedNone => "unsupported None value",
|
Error::UnsupportedNone => "unsupported None value",
|
||||||
Error::Custom(_) => "custom error",
|
Error::Custom(_) => "custom error",
|
||||||
Error::KeyNewline => unreachable!(),
|
Error::KeyNewline => unreachable!(),
|
||||||
|
Error::ArrayMixedType => unreachable!(),
|
||||||
Error::__Nonexhaustive => panic!(),
|
Error::__Nonexhaustive => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,21 +14,6 @@ macro_rules! test( ($name:ident, $s:expr, $msg:expr) => (
|
||||||
fn $name() { bad!($s, $msg); }
|
fn $name() { bad!($s, $msg); }
|
||||||
) );
|
) );
|
||||||
|
|
||||||
test!(
|
|
||||||
array_mixed_types_arrays_and_ints,
|
|
||||||
include_str!("invalid/array-mixed-types-arrays-and-ints.toml"),
|
|
||||||
"mixed types in an array at line 1 column 24"
|
|
||||||
);
|
|
||||||
test!(
|
|
||||||
array_mixed_types_ints_and_floats,
|
|
||||||
include_str!("invalid/array-mixed-types-ints-and-floats.toml"),
|
|
||||||
"mixed types in an array at line 1 column 23"
|
|
||||||
);
|
|
||||||
test!(
|
|
||||||
array_mixed_types_strings_and_ints,
|
|
||||||
include_str!("invalid/array-mixed-types-strings-and-ints.toml"),
|
|
||||||
"mixed types in an array at line 1 column 27"
|
|
||||||
);
|
|
||||||
test!(
|
test!(
|
||||||
datetime_malformed_no_leads,
|
datetime_malformed_no_leads,
|
||||||
include_str!("invalid/datetime-malformed-no-leads.toml"),
|
include_str!("invalid/datetime-malformed-no-leads.toml"),
|
||||||
|
|
|
@ -146,6 +146,21 @@ test!(
|
||||||
include_str!("valid/arrays-nested.toml"),
|
include_str!("valid/arrays-nested.toml"),
|
||||||
include_str!("valid/arrays-nested.json")
|
include_str!("valid/arrays-nested.json")
|
||||||
);
|
);
|
||||||
|
test!(
|
||||||
|
array_mixed_types_ints_and_floats,
|
||||||
|
include_str!("valid/array-mixed-types-ints-and-floats.toml"),
|
||||||
|
include_str!("valid/array-mixed-types-ints-and-floats.json")
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
array_mixed_types_arrays_and_ints,
|
||||||
|
include_str!("valid/array-mixed-types-arrays-and-ints.toml"),
|
||||||
|
include_str!("valid/array-mixed-types-arrays-and-ints.json")
|
||||||
|
);
|
||||||
|
test!(
|
||||||
|
array_mixed_types_strings_and_ints,
|
||||||
|
include_str!("valid/array-mixed-types-strings-and-ints.toml"),
|
||||||
|
include_str!("valid/array-mixed-types-strings-and-ints.json")
|
||||||
|
);
|
||||||
test!(
|
test!(
|
||||||
empty,
|
empty,
|
||||||
include_str!("valid/empty.toml"),
|
include_str!("valid/empty.toml"),
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"arrays-and-ints": {
|
||||||
|
"type": "array",
|
||||||
|
"value": [
|
||||||
|
{"type": "integer", "value": "1"},
|
||||||
|
{"type": "array", "value": [
|
||||||
|
{ "type": "string", "value":"Arrays are not integers."}
|
||||||
|
]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"ints-and-floats": {
|
||||||
|
"type": "array",
|
||||||
|
"value": [
|
||||||
|
{"type": "integer", "value": "1"},
|
||||||
|
{"type": "float", "value": "1.1"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"strings-and-ints": {
|
||||||
|
"type": "array",
|
||||||
|
"value": [
|
||||||
|
{"type": "string", "value": "hi"},
|
||||||
|
{"type": "integer", "value": "42"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -170,7 +170,8 @@ False = false
|
||||||
## Array
|
## Array
|
||||||
|
|
||||||
# Arrays are square brackets with other primitives inside. Whitespace is
|
# Arrays are square brackets with other primitives inside. Whitespace is
|
||||||
# ignored. Elements are separated by commas. Data types may not be mixed.
|
# ignored. Elements are separated by commas. Since 2019-11-06 data types can be
|
||||||
|
# mixed.
|
||||||
|
|
||||||
[array]
|
[array]
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue