Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2 parser #70

Merged
merged 30 commits into from
Oct 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
02da6fb
feat(v2): implement kdl v2 parser and related changes
zkat Apr 6, 2024
41dfb5e
formatting stuff for KdlNode
zkat Apr 6, 2024
364f27e
document format and renaming some things
zkat Apr 6, 2024
bfc66be
prettify compliance test reporting
zkat Apr 7, 2024
4652ee9
fix entry parsing
zkat Apr 7, 2024
a91060e
starting to fix nodes
zkat Apr 7, 2024
28face1
more fixes and debugging
zkat Apr 7, 2024
9002425
more progress!
zkat Apr 7, 2024
45bd6b6
trying to figure out what's going wrong
zkat Aug 1, 2024
4e042c9
making some progress fixing things!
zkat Oct 2, 2024
e58441a
checkpoint
zkat Oct 4, 2024
c58ed1d
multiline strings work now!
zkat Oct 4, 2024
444bd3a
fixes for multiline
zkat Oct 4, 2024
23d3278
newline normalization for multiliners
zkat Oct 4, 2024
618242a
add a test for escline stuff
zkat Oct 4, 2024
8bc5dfa
more compliance fixes
zkat Oct 5, 2024
404e195
compliance fixes
zkat Oct 5, 2024
3d78c6a
i don't know how this got here
zkat Oct 5, 2024
aa4cb22
clean up some TODOs
zkat Oct 5, 2024
c7185fc
parser is fully conformant! all that's left is formatting!!
zkat Oct 5, 2024
3f55cef
passing the whole-ass test suite!!
zkat Oct 5, 2024
792f3a2
fix formatting
zkat Oct 5, 2024
b893c37
fix parsing empty lines in multiline strings
zkat Oct 5, 2024
87bd8a5
more fixes
zkat Oct 5, 2024
75ebbd7
tests passing!
zkat Oct 5, 2024
489a74a
clippy fixes
zkat Oct 5, 2024
d6945ba
some more tweaks
zkat Oct 5, 2024
c0f0a41
simplify value types
zkat Oct 5, 2024
d2fb99b
fix fmt
zkat Oct 5, 2024
71d80a5
more = removal
zkat Oct 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
rust: [1.56.0, stable]
rust: [1.70.0, stable]
os: [ubuntu-latest, macOS-latest, windows-latest]

steps:
Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ default = ["span"]
span = []

[dependencies]
miette = "5.7.0"
miette = "7.2.0"
nom = "7.1.1"
thiserror = "1.0.40"
winnow = { version = "0.6.20", features = ["alloc", "unstable-recover"] }

[dev-dependencies]
miette = { version = "5.7.0", features = ["fancy"] }
miette = { version = "7.2.0", features = ["fancy"] }
pretty_assertions = "1.3.0"
36 changes: 4 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,38 +66,6 @@ assert_eq!(&doc.to_string(), node_str);
[`KdlDocument`], [`KdlNode`], [`KdlEntry`], and [`KdlIdentifier`] can all
be parsed and managed this way.

#### Query Engine

`kdl` includes a query engine for
[KQL](https://github.com/kdl-org/kdl/blob/main/QUERY-SPEC.md), which lets you
pick out nodes from a document using a CSS Selectors-style syntax.

Queries can be done from either a [`KdlDocument`] or a [`KdlNode`], with
mostly the same semantics.

```rust
use kdl::KdlDocument;

let doc = r#"
a {
b 1
c 2
d 3 {
e prop="hello"
}
}
"#.parse::<KdlDocument>().expect("failed to parse KDL");

let results = doc.query("a > b").expect("failed to parse query");
assert_eq!(results, Some(&doc.nodes()[0].children().unwrap().nodes()[0]));

let results = doc.query_get("e", "prop").expect("failed to parse query");
assert_eq!(results, Some(&"hello".into()));

let results = doc.query_get_all("a > []", 0).expect("failed to parse query").collect::<Vec<_>>();
assert_eq!(results, vec![&1.into(), &2.into(), &3.into()]);
```

### Error Reporting

[`KdlError`] implements [`miette::Diagnostic`] and can be used to display
Expand Down Expand Up @@ -154,6 +122,10 @@ means a few things:
you [`KdlDocument::fmt`] in which case the original representation will be
thrown away and the actual value will be used when serializing.

### Minimum Supported Rust Version

You must be at least `1.70.0` tall to get on this ride.

### License

The code in this repository is covered by [the Apache-2.0
Expand Down
6 changes: 3 additions & 3 deletions examples/Cargo.kdl
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package {
name "kdl"
name kdl
version "0.0.0"
description "kat's document language"
description "The kdl document language"
authors "Kat Marchán <kzm@zkat.tech>"
license-file "LICENSE.md"
license-file LICENSE.md
edition "2018"
}

Expand Down
39 changes: 22 additions & 17 deletions examples/ci.kdl
Original file line number Diff line number Diff line change
@@ -1,47 +1,52 @@
// This example is a GitHub Action if it used KDL syntax.
// See .github/workflows/ci.yml for the file this was based on.
name "CI"
name CI

on "push" "pull_request"
on push pull_request

env {
RUSTFLAGS "-Dwarnings"
RUSTFLAGS -Dwarnings
}

jobs {
fmt_and_docs "Check fmt & build docs" {
runs-on "ubuntu-latest"
runs-on ubuntu-latest
steps {
step uses="actions/checkout@v1"
step "Install Rust" uses="actions-rs/toolchain@v1" {
profile "minimal"
toolchain "stable"
components "rustfmt"
override true
profile minimal
toolchain stable
components rustfmt
override #true
}
step "rustfmt" run="cargo fmt --all -- --check"
step "docs" run="cargo doc --no-deps"
step rustfmt { run cargo fmt --all -- --check }
step docs { run cargo doc --no-deps }
}
}
build_and_test "Build & Test" {
runs-on "${{ matrix.os }}"
strategy {
matrix {
rust "1.46.0" "stable"
os "ubuntu-latest" "macOS-latest" "windows-latest"
rust "1.46.0" stable
os ubuntu-latest macOS-latest windows-latest
}
}

steps {
step uses="actions/checkout@v1"
step "Install Rust" uses="actions-rs/toolchain@v1" {
profile "minimal"
profile minimal
toolchain "${{ matrix.rust }}"
components "clippy"
override true
components clippy
override #true
}
step "Clippy" run="cargo clippy --all -- -D warnings"
step "Run tests" run="cargo test --all --verbose"
step Clippy { run cargo clippy --all -- -D warnings }
step "Run tests" { run cargo test --all --verbose }
step "Other Stuff" run="
echo foo
echo bar
echo baz
"
}
}
}
87 changes: 45 additions & 42 deletions examples/custom-errors.rs
Original file line number Diff line number Diff line change
@@ -1,47 +1,50 @@
/// Show how to build your own diagnostics, without having to use the
/// `fancy` feature or having `main()` return `miette::Result`
use kdl::KdlDocument;
use miette::Diagnostic;
use miette::SourceSpan;
// TODO(@zkat): Error stuff has changed, so this needs updating.

#[derive(Debug)]
pub struct MyError {
pub message: String,
}
// /// Show how to build your own diagnostics, without having to use the
// /// `fancy` feature or having `main()` return `miette::Result`
// ///
// use kdl::KdlDocument;
// use miette::Diagnostic;
// use miette::SourceSpan;

fn parse(input: &str) -> Result<KdlDocument, MyError> {
let doc = input.parse::<KdlDocument>();
doc.map_err(|error| {
let source = error
.source_code()
.expect("parse errors should have source code");
let help = error.help.unwrap_or_default();
let span: SourceSpan = error.span;
let contents = source
.read_span(&span, 0, 0)
.expect("source should have span contents");
// miette uses 0 based indexes, but humans prefer 1-based
let line = contents.line() + 1;
let column = contents.column() + 1;
let message = format!(
"line {}, column {}: {}\n help: {}",
line, column, error, help
);
MyError { message }
})
}
// #[derive(Debug)]
// pub struct MyError {
// pub message: String,
// }

// fn parse(input: &str) -> Result<KdlDocument, MyError> {
// let doc = input.parse::<KdlDocument>();
// doc.map_err(|error| {
// let source = error
// .source_code()
// .expect("parse errors should have source code");
// let help = error.help.unwrap_or_default();
// let span: SourceSpan = error.span;
// let contents = source
// .read_span(&span, 0, 0)
// .expect("source should have span contents");
// // miette uses 0 based indexes, but humans prefer 1-based
// let line = contents.line() + 1;
// let column = contents.column() + 1;
// let message = format!(
// "line {}, column {}: {}\n help: {}",
// line, column, error, help
// );
// MyError { message }
// })
// }

fn main() {
let input = r#"
foo {
bar {
baz 1.
}
}
"#;
let err = parse(input).unwrap_err();
eprintln!("{}", err.message);
// Output:
// line 4, column 14: Expected valid value.
// help: Floating point numbers must be base 10, and have numbers after the decimal point.
// let input = r#"
// foo {
// bar {
// baz 1.
// }
// }
// "#;
// let err = parse(input).unwrap_err();
// eprintln!("{}", err.message);
// // Output:
// // line 4, column 14: Expected valid value.
// // help: Floating point numbers must be base 10, and have numbers after the decimal point.
}
2 changes: 1 addition & 1 deletion examples/insert-node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ words {
let word_node = KdlNode::new(identifier);
word_nodes.push(word_node);
word_nodes.sort_by(sort_by_name);
words_section.fmt();
words_section.autoformat();

println!("{}", doc);

Expand Down
Loading
Loading