Skip to content

Commit

Permalink
feat: nicely report compiler errors
Browse files Browse the repository at this point in the history
Extend parser structs with spans to generate nice error reports with
annotated source code, like being done for parser errors.
  • Loading branch information
dnaka91 committed Oct 24, 2023
1 parent 0f69ed5 commit 2737f20
Show file tree
Hide file tree
Showing 32 changed files with 1,991 additions and 491 deletions.
8 changes: 1 addition & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/stef-build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ license.workspace = true

[dependencies]
glob = "0.3.1"
miette.workspace = true
miette = { workspace = true, features = ["fancy-no-backtrace"] }
prettyplease = "0.2.15"
proc-macro2.workspace = true
quote.workspace = true
Expand Down
24 changes: 13 additions & 11 deletions crates/stef-build/src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,11 @@ fn compile_variant(
name,
fields,
id,
..
}: &Variant<'_>,
) -> TokenStream {
let id = proc_macro2::Literal::u32_unsuffixed(id.0);
let name = Ident::new(name, Span::call_site());
let id = proc_macro2::Literal::u32_unsuffixed(id.get());
let name = Ident::new(name.get(), Span::call_site());
let field_vars = compile_field_vars(fields);
let field_matches = compile_field_matches(fields);
let field_assigns = compile_field_assigns(fields);
Expand Down Expand Up @@ -111,7 +112,7 @@ fn compile_variant(
fn compile_field_vars(fields: &Fields<'_>) -> TokenStream {
let vars: Box<dyn Iterator<Item = _>> = match fields {
Fields::Named(named) => Box::new(named.iter().map(|named| {
let name = Ident::new(named.name, Span::call_site());
let name = Ident::new(named.name.get(), Span::call_site());
(name, &named.ty)
})),
Fields::Unnamed(unnamed) => Box::new(unnamed.iter().enumerate().map(|(idx, unnamed)| {
Expand Down Expand Up @@ -143,9 +144,10 @@ fn compile_field_matches(fields: &Fields<'_>) -> TokenStream {
name,
ty,
id,
..
}| {
let id = proc_macro2::Literal::u32_unsuffixed(id.0);
let name = proc_macro2::Ident::new(name, Span::call_site());
let id = proc_macro2::Literal::u32_unsuffixed(id.get());
let name = proc_macro2::Ident::new(name.get(), Span::call_site());
let ty = compile_data_type(if let DataType::Option(ty) = ty {
ty
} else {
Expand All @@ -162,8 +164,8 @@ fn compile_field_matches(fields: &Fields<'_>) -> TokenStream {
let calls = unnamed
.iter()
.enumerate()
.map(|(idx, UnnamedField { ty, id })| {
let id = proc_macro2::Literal::u32_unsuffixed(id.0);
.map(|(idx, UnnamedField { ty, id, .. })| {
let id = proc_macro2::Literal::u32_unsuffixed(id.get());
let name = Ident::new(&format!("n{idx}"), Span::call_site());
let ty = compile_data_type(if let DataType::Option(ty) = ty {
ty
Expand All @@ -184,9 +186,9 @@ fn compile_field_assigns(fields: &Fields<'_>) -> TokenStream {
match fields {
Fields::Named(named) => {
let assigns = named.iter().map(|named| {
let name = Ident::new(named.name, Span::call_site());
let name_lit = proc_macro2::Literal::string(named.name);
let id = proc_macro2::Literal::u32_unsuffixed(named.id.0);
let name = Ident::new(named.name.get(), Span::call_site());
let name_lit = proc_macro2::Literal::string(named.name.get());
let id = proc_macro2::Literal::u32_unsuffixed(named.id.get());

if matches!(named.ty, DataType::Option(_)) {
quote! { #name }
Expand All @@ -203,7 +205,7 @@ fn compile_field_assigns(fields: &Fields<'_>) -> TokenStream {
Fields::Unnamed(unnamed) => {
let assigns = unnamed.iter().enumerate().map(|(idx, unnamed)| {
let name = Ident::new(&format!("n{idx}"), Span::call_site());
let id = proc_macro2::Literal::u32_unsuffixed(unnamed.id.0);
let id = proc_macro2::Literal::u32_unsuffixed(unnamed.id.get());

if matches!(unnamed.ty, DataType::Option(_)) {
quote! { #name }
Expand Down
8 changes: 5 additions & 3 deletions crates/stef-build/src/definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,11 @@ fn compile_variant(
name,
fields,
id: _,
..
}: &Variant<'_>,
) -> TokenStream {
let comment = compile_comment(comment);
let name = Ident::new(name, Span::call_site());
let name = Ident::new(name.get(), Span::call_site());
let fields = compile_fields(fields, false);

quote! {
Expand Down Expand Up @@ -215,10 +216,11 @@ fn compile_fields(fields: &Fields<'_>, for_struct: bool) -> TokenStream {
name,
ty,
id: _,
..
}| {
let comment = compile_comment(comment);
let public = for_struct.then(|| quote! { pub });
let name = Ident::new(name, Span::call_site());
let name = Ident::new(name.get(), Span::call_site());
let ty = compile_data_type(ty);
quote! {
#comment
Expand All @@ -232,7 +234,7 @@ fn compile_fields(fields: &Fields<'_>, for_struct: bool) -> TokenStream {
} }
}
Fields::Unnamed(unnamed) => {
let fields = unnamed.iter().map(|UnnamedField { ty, id: _ }| {
let fields = unnamed.iter().map(|UnnamedField { ty, id: _, .. }| {
let ty = compile_data_type(ty);
quote! { #ty }
});
Expand Down
25 changes: 14 additions & 11 deletions crates/stef-build/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ fn compile_struct_fields(fields: &Fields<'_>) -> TokenStream {
name,
ty,
id,
..
}| {
let id = proc_macro2::Literal::u32_unsuffixed(id.0);
let name = proc_macro2::Ident::new(name, Span::call_site());
let id = proc_macro2::Literal::u32_unsuffixed(id.get());
let name = proc_macro2::Ident::new(name.get(), Span::call_site());

if let DataType::Option(ty) = ty {
let ty = compile_data_type(ty, if is_copy(ty) {
Expand All @@ -67,8 +68,8 @@ fn compile_struct_fields(fields: &Fields<'_>) -> TokenStream {
let calls = unnamed
.iter()
.enumerate()
.map(|(idx, UnnamedField { ty, id })| {
let id = proc_macro2::Literal::u32_unsuffixed(id.0);
.map(|(idx, UnnamedField { ty, id, .. })| {
let id = proc_macro2::Literal::u32_unsuffixed(id.get());
let idx = proc_macro2::Literal::usize_unsuffixed(idx);
let ty = compile_data_type(ty, quote! { self.#idx });

Expand Down Expand Up @@ -120,17 +121,18 @@ fn compile_variant(
name,
fields,
id,
..
}: &Variant<'_>,
) -> TokenStream {
let id = proc_macro2::Literal::u32_unsuffixed(id.0);
let name = Ident::new(name, Span::call_site());
let id = proc_macro2::Literal::u32_unsuffixed(id.get());
let name = Ident::new(name.get(), Span::call_site());
let fields_body = compile_variant_fields(fields);

match fields {
Fields::Named(named) => {
let field_names = named
.iter()
.map(|NamedField { name, .. }| Ident::new(name, Span::call_site()));
.map(|NamedField { name, .. }| Ident::new(name.get(), Span::call_site()));

quote! {
Self::#name{ #(#field_names,)* } => {
Expand Down Expand Up @@ -170,9 +172,10 @@ fn compile_variant_fields(fields: &Fields<'_>) -> TokenStream {
name,
ty,
id,
..
}| {
let id = proc_macro2::Literal::u32_unsuffixed(id.0);
let name = proc_macro2::Ident::new(name, Span::call_site());
let id = proc_macro2::Literal::u32_unsuffixed(id.get());
let name = proc_macro2::Ident::new(name.get(), Span::call_site());

if matches!(ty, DataType::Option(_)) {
quote! { ::stef::buf::encode_field_option(w, #id, &#name); }
Expand All @@ -192,8 +195,8 @@ fn compile_variant_fields(fields: &Fields<'_>) -> TokenStream {
let calls = unnamed
.iter()
.enumerate()
.map(|(idx, UnnamedField { ty, id })| {
let id = proc_macro2::Literal::u32_unsuffixed(id.0);
.map(|(idx, UnnamedField { ty, id, .. })| {
let id = proc_macro2::Literal::u32_unsuffixed(id.get());
let name = Ident::new(&format!("n{idx}"), Span::call_site());
let ty = compile_data_type(ty, quote! { *#name });

Expand Down
35 changes: 23 additions & 12 deletions crates/stef-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::{
path::{Path, PathBuf},
};

use miette::{NamedSource, Report};
use stef_parser::Schema;
use thiserror::Error;

Expand All @@ -17,7 +18,7 @@ mod decode;
mod definition;
mod encode;

type Result<T, E = Error> = std::result::Result<T, E>;
pub type Result<T, E = Error> = std::result::Result<T, E>;

#[derive(Debug, Error)]
pub enum Error {
Expand All @@ -38,17 +39,25 @@ pub enum Error {
source: std::io::Error,
file: PathBuf,
},
#[error("failed parsing schema from {file:?}: {message}")]
Parse { message: String, file: PathBuf },
#[error("failed compiling schema from {file:?}")]
Compile {
#[source]
source: stef_compiler::Error,
file: PathBuf,
},
#[error("failed parsing schema from {file:?}:\n{report:?}")]
Parse { report: Report, file: PathBuf },
#[error("failed compiling schema from {file:?}:\n{report:?}")]
Compile { report: Report, file: PathBuf },
}

pub fn compile(schemas: &[impl AsRef<str>], _includes: &[impl AsRef<Path>]) -> Result<()> {
miette::set_hook(Box::new(|_| {
Box::new(
miette::MietteHandlerOpts::new()
.color(true)
.context_lines(3)
.force_graphical(true)
.terminal_links(true)
.build(),
)
}))
.ok();

let out_dir = PathBuf::from(std::env::var_os("OUT_DIR").unwrap());

for schema in schemas.iter().map(AsRef::as_ref) {
Expand All @@ -64,12 +73,14 @@ pub fn compile(schemas: &[impl AsRef<str>], _includes: &[impl AsRef<Path>]) -> R
})?;

let schema = Schema::parse(&input).map_err(|e| Error::Parse {
message: format!("{e:?}"),
report: e
.with_source_code(NamedSource::new(path.display().to_string(), input.clone())),
file: path.clone(),
})?;

stef_compiler::validate_schema(&schema).map_err(|source| Error::Compile {
source,
stef_compiler::validate_schema(&schema).map_err(|e| Error::Compile {
report: Report::new(e)
.with_source_code(NamedSource::new(path.display().to_string(), input.clone())),
file: path.clone(),
})?;

Expand Down
1 change: 1 addition & 0 deletions crates/stef-compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ repository.workspace = true
license.workspace = true

[dependencies]
miette.workspace = true
stef-parser = { path = "../stef-parser" }
thiserror.workspace = true
Loading

0 comments on commit 2737f20

Please sign in to comment.