diff --git a/Cargo.lock b/Cargo.lock index 10d8c2d..9d8af3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -139,9 +139,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" dependencies = [ "clap_builder", "clap_derive", @@ -149,9 +149,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" dependencies = [ "anstream", "anstyle", @@ -162,9 +162,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", @@ -174,9 +174,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "color-eyre" @@ -721,6 +721,7 @@ dependencies = [ name = "stef-compiler" version = "0.1.0" dependencies = [ + "insta", "miette", "stef-parser", "thiserror", diff --git a/Justfile b/Justfile index fb840b2..2434411 100644 --- a/Justfile +++ b/Justfile @@ -19,6 +19,13 @@ check: fmt: cargo +nightly fmt --all +# Run snapshot tests and review any updates +snapshots: + cargo insta test --workspace --all-features \ + --test-runner nextest \ + --unreferenced delete \ + --review + # Start up the local server for the book @book: cd book && just dev diff --git a/crates/stef-cli/Cargo.toml b/crates/stef-cli/Cargo.toml index 648a3fc..37f0532 100644 --- a/crates/stef-cli/Cargo.toml +++ b/crates/stef-cli/Cargo.toml @@ -14,7 +14,7 @@ name = "stef" path = "src/main.rs" [dependencies] -clap = { version = "4.4.6", features = ["derive", "wrap_help"] } +clap = { version = "4.4.7", features = ["derive", "wrap_help"] } color-eyre.workspace = true glob.workspace = true miette = { workspace = true, features = ["fancy-no-backtrace"] } diff --git a/crates/stef-compiler/Cargo.toml b/crates/stef-compiler/Cargo.toml index 929a1af..5534b60 100644 --- a/crates/stef-compiler/Cargo.toml +++ b/crates/stef-compiler/Cargo.toml @@ -13,3 +13,7 @@ license.workspace = true miette.workspace = true stef-parser = { path = "../stef-parser" } thiserror.workspace = true + +[dev-dependencies] +insta.workspace = true +miette = { workspace = true, features = ["fancy-no-backtrace"] } diff --git a/crates/stef-compiler/src/ids.rs b/crates/stef-compiler/src/ids.rs index e09e496..de39b50 100644 --- a/crates/stef-compiler/src/ids.rs +++ b/crates/stef-compiler/src/ids.rs @@ -40,7 +40,7 @@ pub enum DuplicateFieldId { #[label("used here again")] second: Range, }, - #[error("duplicate ID {} in field {position}, already used in {other_position}", id.get())] + #[error("duplicate ID {} in position {position}, already used at {other_position}", id.get())] #[diagnostic(help("the IDs for each field must be unique"))] Unnamed { id: Id, @@ -116,8 +116,8 @@ fn validate_field_ids(value: &Fields<'_>) -> Result<(), DuplicateFieldId> { visited.insert(field.id.get(), (pos, field.id.span())).map( |(other_position, other_span)| DuplicateFieldId::Unnamed { id: field.id.clone(), - position: pos, - other_position, + position: pos + 1, + other_position: other_position + 1, first: other_span.into(), second: field.id.span().into(), }, diff --git a/crates/stef-compiler/tests/compiler.rs b/crates/stef-compiler/tests/compiler.rs new file mode 100644 index 0000000..5e1f88d --- /dev/null +++ b/crates/stef-compiler/tests/compiler.rs @@ -0,0 +1,43 @@ +use std::{ + fmt::{self, Display}, + fs, +}; + +use insta::{assert_snapshot, glob}; +use miette::{Diagnostic, MietteHandler, MietteHandlerOpts, NamedSource, Report, ReportHandler}; +use stef_parser::Schema; + +#[test] +fn compile_invalid_schema() { + struct Wrapper<'a>(&'a MietteHandler, &'a dyn Diagnostic); + + impl<'a> Display for Wrapper<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.debug(self.1, f) + } + } + + let handler = MietteHandlerOpts::new() + .color(false) + .context_lines(3) + .force_graphical(true) + .terminal_links(false) + .width(120) + .build(); + + glob!("inputs/invalid/*.stef", |path| { + let input = fs::read_to_string(path).unwrap(); + let schema = Schema::parse(input.as_str()).unwrap(); + let result = stef_compiler::validate_schema(&schema).unwrap_err(); + let report = Report::new(result).with_source_code(NamedSource::new( + path.file_name().unwrap().to_string_lossy(), + input, + )); + + assert_snapshot!( + "error", + Wrapper(&handler, &*report).to_string(), + stringify!(stef_compiler::validate_schema(&schema).unwrap_err()) + ); + }); +} diff --git a/crates/stef-compiler/tests/inputs/invalid/enum_gen_dup.stef b/crates/stef-compiler/tests/inputs/invalid/enum_gen_dup.stef new file mode 100644 index 0000000..c2c14a0 --- /dev/null +++ b/crates/stef-compiler/tests/inputs/invalid/enum_gen_dup.stef @@ -0,0 +1,4 @@ +enum Sample { + One @1, + Two { value: T @1 } @2, +} diff --git a/crates/stef-compiler/tests/inputs/invalid/enum_gen_unused.stef b/crates/stef-compiler/tests/inputs/invalid/enum_gen_unused.stef new file mode 100644 index 0000000..68b2df6 --- /dev/null +++ b/crates/stef-compiler/tests/inputs/invalid/enum_gen_unused.stef @@ -0,0 +1,4 @@ +enum Sample { + One @1, + Two { value: string @1 } @2, +} diff --git a/crates/stef-compiler/tests/inputs/invalid/enum_named_dup_id.stef b/crates/stef-compiler/tests/inputs/invalid/enum_named_dup_id.stef new file mode 100644 index 0000000..d3830eb --- /dev/null +++ b/crates/stef-compiler/tests/inputs/invalid/enum_named_dup_id.stef @@ -0,0 +1,7 @@ +enum Sample { + One @1, + Two { + field1: string @1, + field2: string @1, + } @2, +} diff --git a/crates/stef-compiler/tests/inputs/invalid/enum_named_dup_name.stef b/crates/stef-compiler/tests/inputs/invalid/enum_named_dup_name.stef new file mode 100644 index 0000000..72b544e --- /dev/null +++ b/crates/stef-compiler/tests/inputs/invalid/enum_named_dup_name.stef @@ -0,0 +1,7 @@ +enum Sample { + One @1, + Two { + field: string @1, + field: string @2, + } @2, +} diff --git a/crates/stef-compiler/tests/inputs/invalid/enum_unnamed_dup_id.stef b/crates/stef-compiler/tests/inputs/invalid/enum_unnamed_dup_id.stef new file mode 100644 index 0000000..de5071b --- /dev/null +++ b/crates/stef-compiler/tests/inputs/invalid/enum_unnamed_dup_id.stef @@ -0,0 +1,4 @@ +enum Sample { + One @1, + Two(string @1, string @1) @2, +} diff --git a/crates/stef-compiler/tests/inputs/invalid/enum_variant_dup_id.stef b/crates/stef-compiler/tests/inputs/invalid/enum_variant_dup_id.stef new file mode 100644 index 0000000..93d710b --- /dev/null +++ b/crates/stef-compiler/tests/inputs/invalid/enum_variant_dup_id.stef @@ -0,0 +1,4 @@ +enum Sample { + One @1, + Two @1, +} diff --git a/crates/stef-compiler/tests/inputs/invalid/enum_variant_dup_name.stef b/crates/stef-compiler/tests/inputs/invalid/enum_variant_dup_name.stef new file mode 100644 index 0000000..bd0d415 --- /dev/null +++ b/crates/stef-compiler/tests/inputs/invalid/enum_variant_dup_name.stef @@ -0,0 +1,4 @@ +enum Sample { + One @1, + One @2, +} diff --git a/crates/stef-compiler/tests/inputs/invalid/struct_gen_dup.stef b/crates/stef-compiler/tests/inputs/invalid/struct_gen_dup.stef new file mode 100644 index 0000000..623415e --- /dev/null +++ b/crates/stef-compiler/tests/inputs/invalid/struct_gen_dup.stef @@ -0,0 +1,3 @@ +struct Sample { + value: T @1, +} diff --git a/crates/stef-compiler/tests/inputs/invalid/struct_gen_unused.stef b/crates/stef-compiler/tests/inputs/invalid/struct_gen_unused.stef new file mode 100644 index 0000000..00cc4e2 --- /dev/null +++ b/crates/stef-compiler/tests/inputs/invalid/struct_gen_unused.stef @@ -0,0 +1,3 @@ +struct Sample { + value: string @1, +} diff --git a/crates/stef-compiler/tests/inputs/invalid/struct_named_dup_id.stef b/crates/stef-compiler/tests/inputs/invalid/struct_named_dup_id.stef new file mode 100644 index 0000000..78a88a0 --- /dev/null +++ b/crates/stef-compiler/tests/inputs/invalid/struct_named_dup_id.stef @@ -0,0 +1,4 @@ +struct Sample { + field1: string @1, + field2: string @1, +} diff --git a/crates/stef-compiler/tests/inputs/invalid/struct_named_dup_name.stef b/crates/stef-compiler/tests/inputs/invalid/struct_named_dup_name.stef new file mode 100644 index 0000000..bdbd7ae --- /dev/null +++ b/crates/stef-compiler/tests/inputs/invalid/struct_named_dup_name.stef @@ -0,0 +1,4 @@ +struct Sample { + field: string @1, + field: string @2, +} diff --git a/crates/stef-compiler/tests/inputs/invalid/struct_unnamed_dup_id.stef b/crates/stef-compiler/tests/inputs/invalid/struct_unnamed_dup_id.stef new file mode 100644 index 0000000..1f681f4 --- /dev/null +++ b/crates/stef-compiler/tests/inputs/invalid/struct_unnamed_dup_id.stef @@ -0,0 +1 @@ +struct Sample(string @1, string @1) diff --git a/crates/stef-compiler/tests/snapshots/compiler__error@enum_gen_dup.stef.snap b/crates/stef-compiler/tests/snapshots/compiler__error@enum_gen_dup.stef.snap new file mode 100644 index 0000000..f85ed16 --- /dev/null +++ b/crates/stef-compiler/tests/snapshots/compiler__error@enum_gen_dup.stef.snap @@ -0,0 +1,19 @@ +--- +source: crates/stef-compiler/tests/compiler.rs +expression: "stef_compiler :: validate_schema(& schema).unwrap_err()" +input_file: crates/stef-compiler/tests/inputs/invalid/enum_gen_dup.stef +--- + × invalid generic type found + ├─▶ duplicate generic type name found + ╰─▶ duplicate generic type name `T` + ╭─[enum_gen_dup.stef:1:1] + 1 │ enum Sample { + · ┬ ┬ + · │ ╰── used here again + · ╰── first declared here + 2 │ One @1, + 3 │ Two { value: T @1 } @2, + 4 │ } + ╰──── + help: the names of each generic type must be unique + diff --git a/crates/stef-compiler/tests/snapshots/compiler__error@enum_gen_unused.stef.snap b/crates/stef-compiler/tests/snapshots/compiler__error@enum_gen_unused.stef.snap new file mode 100644 index 0000000..2a54cce --- /dev/null +++ b/crates/stef-compiler/tests/snapshots/compiler__error@enum_gen_unused.stef.snap @@ -0,0 +1,18 @@ +--- +source: crates/stef-compiler/tests/compiler.rs +expression: "stef_compiler :: validate_schema(& schema).unwrap_err()" +input_file: crates/stef-compiler/tests/inputs/invalid/enum_gen_unused.stef +--- + × invalid generic type found + ├─▶ unused generic type argument found + ╰─▶ unused generic type argument `T` + ╭─[enum_gen_unused.stef:1:1] + 1 │ enum Sample { + · ┬ + · ╰── declared here + 2 │ One @1, + 3 │ Two { value: string @1 } @2, + 4 │ } + ╰──── + help: each declared generic must be used in some way + diff --git a/crates/stef-compiler/tests/snapshots/compiler__error@enum_named_dup_id.stef.snap b/crates/stef-compiler/tests/snapshots/compiler__error@enum_named_dup_id.stef.snap new file mode 100644 index 0000000..a9f40e8 --- /dev/null +++ b/crates/stef-compiler/tests/snapshots/compiler__error@enum_named_dup_id.stef.snap @@ -0,0 +1,23 @@ +--- +source: crates/stef-compiler/tests/compiler.rs +expression: "stef_compiler :: validate_schema(& schema).unwrap_err()" +input_file: crates/stef-compiler/tests/inputs/invalid/enum_named_dup_id.stef +--- + × duplicate ID found + ├─▶ duplicate ID in a field + ╰─▶ duplicate ID 1 in field `field2`, already used in `field1` + ╭─[enum_named_dup_id.stef:1:1] + 1 │ enum Sample { + 2 │ One @1, + 3 │ Two { + 4 │ field1: string @1, + · ─┬ + · ╰── first declared here + 5 │ field2: string @1, + · ─┬ + · ╰── used here again + 6 │ } @2, + 7 │ } + ╰──── + help: the IDs for each field must be unique + diff --git a/crates/stef-compiler/tests/snapshots/compiler__error@enum_named_dup_name.stef.snap b/crates/stef-compiler/tests/snapshots/compiler__error@enum_named_dup_name.stef.snap new file mode 100644 index 0000000..e63e045 --- /dev/null +++ b/crates/stef-compiler/tests/snapshots/compiler__error@enum_named_dup_name.stef.snap @@ -0,0 +1,23 @@ +--- +source: crates/stef-compiler/tests/compiler.rs +expression: "stef_compiler :: validate_schema(& schema).unwrap_err()" +input_file: crates/stef-compiler/tests/inputs/invalid/enum_named_dup_name.stef +--- + × duplicate name found + ├─▶ duplicate name in a field + ╰─▶ duplicate field name `field` + ╭─[enum_named_dup_name.stef:1:1] + 1 │ enum Sample { + 2 │ One @1, + 3 │ Two { + 4 │ field: string @1, + · ──┬── + · ╰── first declared here + 5 │ field: string @2, + · ──┬── + · ╰── used here again + 6 │ } @2, + 7 │ } + ╰──── + help: the names of each field must be unique + diff --git a/crates/stef-compiler/tests/snapshots/compiler__error@enum_unnamed_dup_id.stef.snap b/crates/stef-compiler/tests/snapshots/compiler__error@enum_unnamed_dup_id.stef.snap new file mode 100644 index 0000000..ecd654e --- /dev/null +++ b/crates/stef-compiler/tests/snapshots/compiler__error@enum_unnamed_dup_id.stef.snap @@ -0,0 +1,19 @@ +--- +source: crates/stef-compiler/tests/compiler.rs +expression: "stef_compiler :: validate_schema(& schema).unwrap_err()" +input_file: crates/stef-compiler/tests/inputs/invalid/enum_unnamed_dup_id.stef +--- + × duplicate ID found + ├─▶ duplicate ID in a field + ╰─▶ duplicate ID 1 in position 2, already used at 1 + ╭─[enum_unnamed_dup_id.stef:1:1] + 1 │ enum Sample { + 2 │ One @1, + 3 │ Two(string @1, string @1) @2, + · ─┬ ─┬ + · │ ╰── used here again + · ╰── first declared here + 4 │ } + ╰──── + help: the IDs for each field must be unique + diff --git a/crates/stef-compiler/tests/snapshots/compiler__error@enum_variant_dup_id.stef.snap b/crates/stef-compiler/tests/snapshots/compiler__error@enum_variant_dup_id.stef.snap new file mode 100644 index 0000000..1b19dc1 --- /dev/null +++ b/crates/stef-compiler/tests/snapshots/compiler__error@enum_variant_dup_id.stef.snap @@ -0,0 +1,20 @@ +--- +source: crates/stef-compiler/tests/compiler.rs +expression: "stef_compiler :: validate_schema(& schema).unwrap_err()" +input_file: crates/stef-compiler/tests/inputs/invalid/enum_variant_dup_id.stef +--- + × duplicate ID found + ├─▶ duplicate ID in an enum variant + ╰─▶ duplicate ID 1 in enum variant `Two`, already used in `One` + ╭─[enum_variant_dup_id.stef:1:1] + 1 │ enum Sample { + 2 │ One @1, + · ─┬ + · ╰── first declared here + 3 │ Two @1, + · ─┬ + · ╰── used here again + 4 │ } + ╰──── + help: the IDs for each variant of an enum must be unique + diff --git a/crates/stef-compiler/tests/snapshots/compiler__error@enum_variant_dup_name.stef.snap b/crates/stef-compiler/tests/snapshots/compiler__error@enum_variant_dup_name.stef.snap new file mode 100644 index 0000000..57f2a3b --- /dev/null +++ b/crates/stef-compiler/tests/snapshots/compiler__error@enum_variant_dup_name.stef.snap @@ -0,0 +1,20 @@ +--- +source: crates/stef-compiler/tests/compiler.rs +expression: "stef_compiler :: validate_schema(& schema).unwrap_err()" +input_file: crates/stef-compiler/tests/inputs/invalid/enum_variant_dup_name.stef +--- + × duplicate name found + ├─▶ duplicate name in an enum variant + ╰─▶ duplicate variant name `One` in enum + ╭─[enum_variant_dup_name.stef:1:1] + 1 │ enum Sample { + 2 │ One @1, + · ─┬─ + · ╰── first declared here + 3 │ One @2, + · ─┬─ + · ╰── used here again + 4 │ } + ╰──── + help: the names of each variant must be unique + diff --git a/crates/stef-compiler/tests/snapshots/compiler__error@struct_gen_dup.stef.snap b/crates/stef-compiler/tests/snapshots/compiler__error@struct_gen_dup.stef.snap new file mode 100644 index 0000000..c834edc --- /dev/null +++ b/crates/stef-compiler/tests/snapshots/compiler__error@struct_gen_dup.stef.snap @@ -0,0 +1,18 @@ +--- +source: crates/stef-compiler/tests/compiler.rs +expression: "stef_compiler :: validate_schema(& schema).unwrap_err()" +input_file: crates/stef-compiler/tests/inputs/invalid/struct_gen_dup.stef +--- + × invalid generic type found + ├─▶ duplicate generic type name found + ╰─▶ duplicate generic type name `T` + ╭─[struct_gen_dup.stef:1:1] + 1 │ struct Sample { + · ┬ ┬ + · │ ╰── used here again + · ╰── first declared here + 2 │ value: T @1, + 3 │ } + ╰──── + help: the names of each generic type must be unique + diff --git a/crates/stef-compiler/tests/snapshots/compiler__error@struct_gen_unused.stef.snap b/crates/stef-compiler/tests/snapshots/compiler__error@struct_gen_unused.stef.snap new file mode 100644 index 0000000..1d5a4b2 --- /dev/null +++ b/crates/stef-compiler/tests/snapshots/compiler__error@struct_gen_unused.stef.snap @@ -0,0 +1,17 @@ +--- +source: crates/stef-compiler/tests/compiler.rs +expression: "stef_compiler :: validate_schema(& schema).unwrap_err()" +input_file: crates/stef-compiler/tests/inputs/invalid/struct_gen_unused.stef +--- + × invalid generic type found + ├─▶ unused generic type argument found + ╰─▶ unused generic type argument `T` + ╭─[struct_gen_unused.stef:1:1] + 1 │ struct Sample { + · ┬ + · ╰── declared here + 2 │ value: string @1, + 3 │ } + ╰──── + help: each declared generic must be used in some way + diff --git a/crates/stef-compiler/tests/snapshots/compiler__error@struct_named_dup_id.stef.snap b/crates/stef-compiler/tests/snapshots/compiler__error@struct_named_dup_id.stef.snap new file mode 100644 index 0000000..f232350 --- /dev/null +++ b/crates/stef-compiler/tests/snapshots/compiler__error@struct_named_dup_id.stef.snap @@ -0,0 +1,20 @@ +--- +source: crates/stef-compiler/tests/compiler.rs +expression: "stef_compiler :: validate_schema(& schema).unwrap_err()" +input_file: crates/stef-compiler/tests/inputs/invalid/struct_named_dup_id.stef +--- + × duplicate ID found + ├─▶ duplicate ID in a field + ╰─▶ duplicate ID 1 in field `field2`, already used in `field1` + ╭─[struct_named_dup_id.stef:1:1] + 1 │ struct Sample { + 2 │ field1: string @1, + · ─┬ + · ╰── first declared here + 3 │ field2: string @1, + · ─┬ + · ╰── used here again + 4 │ } + ╰──── + help: the IDs for each field must be unique + diff --git a/crates/stef-compiler/tests/snapshots/compiler__error@struct_named_dup_name.stef.snap b/crates/stef-compiler/tests/snapshots/compiler__error@struct_named_dup_name.stef.snap new file mode 100644 index 0000000..cfd9cb1 --- /dev/null +++ b/crates/stef-compiler/tests/snapshots/compiler__error@struct_named_dup_name.stef.snap @@ -0,0 +1,20 @@ +--- +source: crates/stef-compiler/tests/compiler.rs +expression: "stef_compiler :: validate_schema(& schema).unwrap_err()" +input_file: crates/stef-compiler/tests/inputs/invalid/struct_named_dup_name.stef +--- + × duplicate name found + ├─▶ duplicate name in a field + ╰─▶ duplicate field name `field` + ╭─[struct_named_dup_name.stef:1:1] + 1 │ struct Sample { + 2 │ field: string @1, + · ──┬── + · ╰── first declared here + 3 │ field: string @2, + · ──┬── + · ╰── used here again + 4 │ } + ╰──── + help: the names of each field must be unique + diff --git a/crates/stef-compiler/tests/snapshots/compiler__error@struct_unnamed_dup_id.stef.snap b/crates/stef-compiler/tests/snapshots/compiler__error@struct_unnamed_dup_id.stef.snap new file mode 100644 index 0000000..75643d4 --- /dev/null +++ b/crates/stef-compiler/tests/snapshots/compiler__error@struct_unnamed_dup_id.stef.snap @@ -0,0 +1,16 @@ +--- +source: crates/stef-compiler/tests/compiler.rs +expression: "stef_compiler :: validate_schema(& schema).unwrap_err()" +input_file: crates/stef-compiler/tests/inputs/invalid/struct_unnamed_dup_id.stef +--- + × duplicate ID found + ├─▶ duplicate ID in a field + ╰─▶ duplicate ID 1 in position 2, already used at 1 + ╭─[struct_unnamed_dup_id.stef:1:1] + 1 │ struct Sample(string @1, string @1) + · ─┬ ─┬ + · │ ╰── used here again + · ╰── first declared here + ╰──── + help: the IDs for each field must be unique +