Skip to content

Commit

Permalink
fix(parser): Failed on mixed inline tables
Browse files Browse the repository at this point in the history
  • Loading branch information
epage committed Oct 3, 2023
1 parent e1f2037 commit 7eaf286
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 13 deletions.
7 changes: 1 addition & 6 deletions crates/toml/tests/decoder_compliance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@ mod decoder;
fn main() {
let decoder = decoder::Decoder;
let mut harness = toml_test_harness::DecoderHarness::new(decoder);
harness
.ignore([
"valid/spec/float-0.toml",
"invalid/inline-table/nested_key_conflict.toml",
])
.unwrap();
harness.ignore(["valid/spec/float-0.toml"]).unwrap();
harness.version("1.0.0");
harness.test();
}
Expand Down
28 changes: 28 additions & 0 deletions crates/toml_edit/src/inline_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use crate::{InternalString, Item, KeyMut, RawString, Table, Value};
pub struct InlineTable {
// `preamble` represents whitespaces in an empty table
preamble: RawString,
// Whether to hide an empty table
pub(crate) implicit: bool,
// prefix before `{` and suffix after `}`
decor: Decor,
pub(crate) span: Option<std::ops::Range<usize>>,
Expand Down Expand Up @@ -133,6 +135,32 @@ impl InlineTable {
}
}

/// If a table has no key/value pairs and implicit, it will not be displayed.
///
/// # Examples
///
/// ```notrust
/// [target."x86_64/windows.json".dependencies]
/// ```
///
/// In the document above, tables `target` and `target."x86_64/windows.json"` are implicit.
///
/// ```
/// use toml_edit::Document;
/// let mut doc = "[a]\n[a.b]\n".parse::<Document>().expect("invalid toml");
///
/// doc["a"].as_table_mut().unwrap().set_implicit(true);
/// assert_eq!(doc.to_string(), "[a.b]\n");
/// ```
pub(crate) fn set_implicit(&mut self, implicit: bool) {
self.implicit = implicit;
}

/// If a table has no key/value pairs and implicit, it will not be displayed.
pub(crate) fn is_implicit(&self) -> bool {
self.implicit
}

/// Change this table's dotted status
pub fn set_dotted(&mut self, yes: bool) {
self.dotted = yes;
Expand Down
23 changes: 22 additions & 1 deletion crates/toml_edit/src/parser/inline_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ fn table_from_pairs(

for (path, kv) in v {
let table = descend_path(&mut root, &path)?;

// "Likewise, using dotted keys to redefine tables already defined in [table] form is not allowed"
let mixed_table_types = table.is_dotted() == path.is_empty();
if mixed_table_types {
return Err(CustomError::DuplicateKey {
key: kv.key.get().into(),
table: None,
});
}

let key: InternalString = kv.key.get_internal().into();
match table.items.entry(key) {
Entry::Vacant(o) => {
Expand All @@ -64,15 +74,26 @@ fn descend_path<'a>(
mut table: &'a mut InlineTable,
path: &'a [Key],
) -> Result<&'a mut InlineTable, CustomError> {
let dotted = !path.is_empty();
for (i, key) in path.iter().enumerate() {
let entry = table.entry_format(key).or_insert_with(|| {
let mut new_table = InlineTable::new();
new_table.set_dotted(true);
new_table.set_implicit(dotted);
new_table.set_dotted(dotted);

Value::InlineTable(new_table)
});
match *entry {
Value::InlineTable(ref mut sweet_child_of_mine) => {
// Since tables cannot be defined more than once, redefining such tables using a
// [table] header is not allowed. Likewise, using dotted keys to redefine tables
// already defined in [table] form is not allowed.
if dotted && !sweet_child_of_mine.is_implicit() {
return Err(CustomError::DuplicateKey {
key: key.get().into(),
table: None,
});
}
table = sweet_child_of_mine;
}
ref v => {
Expand Down
7 changes: 1 addition & 6 deletions crates/toml_edit/tests/decoder_compliance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@ mod decoder;
fn main() {
let decoder = decoder::Decoder;
let mut harness = toml_test_harness::DecoderHarness::new(decoder);
harness
.ignore([
"valid/spec/float-0.toml",
"invalid/inline-table/nested_key_conflict.toml",
])
.unwrap();
harness.ignore(["valid/spec/float-0.toml"]).unwrap();
harness.version("1.0.0");
harness.test();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
TOML parse error at line 1, column 8
|
1 | tbl = { fruit = { apple.color = "red" }, fruit.apple.texture = { smooth = true } }
| ^
duplicate key `fruit`

0 comments on commit 7eaf286

Please sign in to comment.