Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
1
vendor/miette-derive/.cargo-checksum.json
vendored
Normal file
1
vendor/miette-derive/.cargo-checksum.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"files":{"Cargo.toml":"599ac29de32593292836994f2f10f64950344d3c052f142fa9d0512d652af53c","LICENSE":"610432849befa0e875d601d044e7e5441eb86c83d052681b23aef357b2a0b928","src/code.rs":"a66b16975c657e931bf650617c1652efed89710fdf7d8610f300f6538cdd9ad6","src/diagnostic.rs":"137e53721f10bf12f7bcd47dd699f3c7a44dad1fe7284b6924624c9853e96803","src/diagnostic_arg.rs":"6cc263379779b42e57152399bd8cc3ec872f7c047696705379cee9e147fc4156","src/diagnostic_source.rs":"e99b8decaa0d4dced2a0fd0667ebe348a6ff0169fc1298859c1a656d754ea86c","src/fmt.rs":"de956c7bdcf44458bb77d029c402e8aae3b97fc8de450710824e4b88f059229e","src/forward.rs":"778ab4ce5455efa9b9673ec83ddfae4b7064a4bf57a674a09fd40ef3b2ff2ff7","src/help.rs":"fa141050182100265174e40957d355dfa175d12822e6ef8ed2e5ba3e41abf991","src/label.rs":"762a5728672cd1ed1587bd048b43ea4ffd0974d49d976b3cf0f4282c8633f02a","src/lib.rs":"92aa427146667829d4faa2cf11da57defdedaa0f237384f3bfd7d8a0a593116f","src/related.rs":"fa6af1336fc6184f6727390757fa732d32cde249907fec56638f9a5f41bfcf45","src/severity.rs":"70fc6c592a0ad39fe9414b7115c7e0fb3e64eaa3ba5bef6b34ac35ad08ec6aa2","src/source_code.rs":"c3c8bf539dae2de0b0bc63ccf70dd4973b0516d9b95e9ac4190fa7468cce63de","src/url.rs":"b0ab232341844c0a3d604716624da8a9edcdb9cffbb188e008bfcc3f3046fe25","src/utils.rs":"db268d54ecc04bbba4cfb9b5a7b8b09922b2e4da396fdd47dd955b97a38740a2"},"package":"49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c"}
|
31
vendor/miette-derive/Cargo.toml
vendored
Normal file
31
vendor/miette-derive/Cargo.toml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "miette-derive"
|
||||
version = "5.10.0"
|
||||
authors = ["Kat Marchán <kzm@zkat.tech>"]
|
||||
description = "Derive macros for miette. Like `thiserror` for Diagnostics."
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/zkat/miette"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies.proc-macro2]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.quote]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.syn]
|
||||
version = "2.0.11"
|
229
vendor/miette-derive/LICENSE
vendored
Normal file
229
vendor/miette-derive/LICENSE
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
Apache License
|
||||
|
||||
Version 2.0, January 2004
|
||||
|
||||
http://www.apache.org/licenses/ TERMS
|
||||
AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
|
||||
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
|
||||
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
|
||||
|
||||
"Legal Entity" shall mean the
|
||||
union of the acting entity and all other entities that control, are controlled
|
||||
by, or are under common control with that entity. For the purposes of this
|
||||
definition, "control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or otherwise, or (ii)
|
||||
ownership of fifty percent (50%) or more of the outstanding shares, or (iii)
|
||||
beneficial ownership of such entity.
|
||||
|
||||
|
||||
|
||||
"You" (or "Your") shall mean
|
||||
an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
|
||||
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation source, and
|
||||
configuration files.
|
||||
|
||||
|
||||
|
||||
"Object" form shall mean any form resulting
|
||||
from mechanical transformation or translation of a Source form, including but not
|
||||
limited to compiled object code, generated documentation, and conversions to
|
||||
other media types.
|
||||
|
||||
|
||||
|
||||
"Work" shall mean the work of authorship,
|
||||
whether in Source or Object form, made available under the License, as indicated
|
||||
by a copyright notice that is included in or attached to the work (an example is
|
||||
provided in the Appendix below).
|
||||
|
||||
|
||||
|
||||
"Derivative Works" shall mean any
|
||||
work, whether in Source or Object form, that is based on (or derived from) the
|
||||
Work and for which the editorial revisions, annotations, elaborations, or other
|
||||
modifications represent, as a whole, an original work of authorship. For the
|
||||
purposes of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of, the Work
|
||||
and Derivative Works thereof.
|
||||
|
||||
|
||||
|
||||
"Contribution" shall mean any work
|
||||
of authorship, including the original version of the Work and any modifications
|
||||
or additions to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner or by an
|
||||
individual or Legal Entity authorized to submit on behalf of the copyright owner.
|
||||
For the purposes of this definition, "submitted" means any form of electronic,
|
||||
verbal, or written communication sent to the Licensor or its representatives,
|
||||
including but not limited to communication on electronic mailing lists, source
|
||||
code control systems, and issue tracking systems that are managed by, or on
|
||||
behalf of, the Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise designated in
|
||||
writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
|
||||
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of
|
||||
whom a Contribution has been received by Licensor and subsequently incorporated
|
||||
within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and
|
||||
conditions of this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license
|
||||
to reproduce, prepare Derivative Works of, publicly display, publicly perform,
|
||||
sublicense, and distribute the Work and such Derivative Works in Source or Object
|
||||
form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this
|
||||
License, each Contributor hereby grants to You a perpetual, worldwide,
|
||||
non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this
|
||||
section) patent license to make, have made, use, offer to sell, sell, import, and
|
||||
otherwise transfer the Work, where such license applies only to those patent
|
||||
claims licensable by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s) with the Work to
|
||||
which such Contribution(s) was submitted. If You institute patent litigation
|
||||
against any entity (including a cross-claim or counterclaim in a lawsuit)
|
||||
alleging that the Work or a Contribution incorporated within the Work constitutes
|
||||
direct or contributory patent infringement, then any patent licenses granted to
|
||||
You under this License for that Work shall terminate as of the date such
|
||||
litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute
|
||||
copies of the Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You meet the following
|
||||
conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any
|
||||
modified files to carry prominent notices stating that You changed the files;
|
||||
and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works that
|
||||
You distribute, all copyright, patent, trademark, and attribution notices from
|
||||
the Source form of the Work, excluding those notices that do not pertain to any
|
||||
part of the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text
|
||||
file as part of its distribution, then any Derivative Works that You distribute
|
||||
must include a readable copy of the attribution notices contained within such
|
||||
NOTICE file, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works, in at least one of the following places: within a NOTICE text
|
||||
file distributed as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or, within a display
|
||||
generated by the Derivative Works, if and wherever such third-party notices
|
||||
normally appear. The contents of the NOTICE file are for informational purposes
|
||||
only and do not modify the License. You may add Your own attribution notices
|
||||
within Derivative Works that You distribute, alongside or as an addendum to the
|
||||
NOTICE text from the Work, provided that such additional attribution notices
|
||||
cannot be construed as modifying the License.
|
||||
|
||||
You may add Your own
|
||||
copyright statement to Your modifications and may provide additional or different
|
||||
license terms and conditions for use, reproduction, or distribution of Your
|
||||
modifications, or for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with the conditions
|
||||
stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly
|
||||
state otherwise, any Contribution intentionally submitted for inclusion in the
|
||||
Work by You to the Licensor shall be under the terms and conditions of this
|
||||
License, without any additional terms or conditions. Notwithstanding the above,
|
||||
nothing herein shall supersede or modify the terms of any separate license
|
||||
agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names,
|
||||
trademarks, service marks, or product names of the Licensor, except as required
|
||||
for reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless
|
||||
required by applicable law or agreed to in writing, Licensor provides the Work
|
||||
(and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including,
|
||||
without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT,
|
||||
MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible
|
||||
for determining the appropriateness of using or redistributing the Work and
|
||||
assume any risks associated with Your exercise of permissions under this
|
||||
License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise, unless required
|
||||
by applicable law (such as deliberate and grossly negligent acts) or agreed to in
|
||||
writing, shall any Contributor be liable to You for damages, including any
|
||||
direct, indirect, special, incidental, or consequential damages of any character
|
||||
arising as a result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill, work stoppage,
|
||||
computer failure or malfunction, or any and all other commercial damages or
|
||||
losses), even if such Contributor has been advised of the possibility of such
|
||||
damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer, and charge a fee
|
||||
for, acceptance of support, warranty, indemnity, or other liability obligations
|
||||
and/or rights consistent with this License. However, in accepting such
|
||||
obligations, You may act only on Your own behalf and on Your sole responsibility,
|
||||
not on behalf of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability incurred by, or
|
||||
claims asserted against, such Contributor by reason of your accepting any such
|
||||
warranty or additional liability. END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to
|
||||
apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work,
|
||||
attach the following boilerplate notice, with the fields enclosed by brackets
|
||||
"[]" replaced with your own identifying information. (Don't include the
|
||||
brackets!) The text should be enclosed in the appropriate comment syntax for the
|
||||
file format. We also recommend that a file or class name and description of
|
||||
purpose be included on the same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] Kat
|
||||
Marchán
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
you may
|
||||
not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy
|
||||
of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by
|
||||
applicable law or agreed to in writing, software
|
||||
|
||||
distributed under the License
|
||||
is distributed on an "AS IS" BASIS,
|
||||
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied.
|
||||
|
||||
See the License for the specific language
|
||||
governing permissions and
|
||||
|
||||
limitations under the License.
|
80
vendor/miette-derive/src/code.rs
vendored
Normal file
80
vendor/miette-derive/src/code.rs
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
parenthesized,
|
||||
parse::{Parse, ParseStream},
|
||||
Token,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
|
||||
forward::WhichFn,
|
||||
utils::gen_all_variants_with,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Code(pub String);
|
||||
|
||||
impl Parse for Code {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let ident = input.parse::<syn::Ident>()?;
|
||||
if ident == "code" {
|
||||
let la = input.lookahead1();
|
||||
if la.peek(syn::token::Paren) {
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
let la = content.lookahead1();
|
||||
if la.peek(syn::LitStr) {
|
||||
let str = content.parse::<syn::LitStr>()?;
|
||||
Ok(Code(str.value()))
|
||||
} else {
|
||||
let path = content.parse::<syn::Path>()?;
|
||||
Ok(Code(
|
||||
path.segments
|
||||
.iter()
|
||||
.map(|s| s.ident.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("::"),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
input.parse::<Token![=]>()?;
|
||||
Ok(Code(input.parse::<syn::LitStr>()?.value()))
|
||||
}
|
||||
} else {
|
||||
Err(syn::Error::new(ident.span(), "diagnostic code is required. Use #[diagnostic(code = ...)] or #[diagnostic(code(...))] to define one."))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Code {
|
||||
pub(crate) fn gen_enum(variants: &[DiagnosticDef]) -> Option<TokenStream> {
|
||||
gen_all_variants_with(
|
||||
variants,
|
||||
WhichFn::Code,
|
||||
|ident, fields, DiagnosticConcreteArgs { code, .. }| {
|
||||
let code = &code.as_ref()?.0;
|
||||
Some(match fields {
|
||||
syn::Fields::Named(_) => {
|
||||
quote! { Self::#ident { .. } => std::option::Option::Some(std::boxed::Box::new(#code)), }
|
||||
}
|
||||
syn::Fields::Unnamed(_) => {
|
||||
quote! { Self::#ident(..) => std::option::Option::Some(std::boxed::Box::new(#code)), }
|
||||
}
|
||||
syn::Fields::Unit => {
|
||||
quote! { Self::#ident => std::option::Option::Some(std::boxed::Box::new(#code)), }
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn gen_struct(&self) -> Option<TokenStream> {
|
||||
let code = &self.0;
|
||||
Some(quote! {
|
||||
fn code(&self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>> {
|
||||
std::option::Option::Some(std::boxed::Box::new(#code))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
397
vendor/miette-derive/src/diagnostic.rs
vendored
Normal file
397
vendor/miette-derive/src/diagnostic.rs
vendored
Normal file
@@ -0,0 +1,397 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{punctuated::Punctuated, DeriveInput, Token};
|
||||
|
||||
use crate::code::Code;
|
||||
use crate::diagnostic_arg::DiagnosticArg;
|
||||
use crate::diagnostic_source::DiagnosticSource;
|
||||
use crate::forward::{Forward, WhichFn};
|
||||
use crate::help::Help;
|
||||
use crate::label::Labels;
|
||||
use crate::related::Related;
|
||||
use crate::severity::Severity;
|
||||
use crate::source_code::SourceCode;
|
||||
use crate::url::Url;
|
||||
|
||||
pub enum Diagnostic {
|
||||
Struct {
|
||||
generics: syn::Generics,
|
||||
ident: syn::Ident,
|
||||
fields: syn::Fields,
|
||||
args: DiagnosticDefArgs,
|
||||
},
|
||||
Enum {
|
||||
ident: syn::Ident,
|
||||
generics: syn::Generics,
|
||||
variants: Vec<DiagnosticDef>,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct DiagnosticDef {
|
||||
pub ident: syn::Ident,
|
||||
pub fields: syn::Fields,
|
||||
pub args: DiagnosticDefArgs,
|
||||
}
|
||||
|
||||
pub enum DiagnosticDefArgs {
|
||||
Transparent(Forward),
|
||||
Concrete(Box<DiagnosticConcreteArgs>),
|
||||
}
|
||||
|
||||
impl DiagnosticDefArgs {
|
||||
pub(crate) fn forward_or_override_enum(
|
||||
&self,
|
||||
variant: &syn::Ident,
|
||||
which_fn: WhichFn,
|
||||
mut f: impl FnMut(&DiagnosticConcreteArgs) -> Option<TokenStream>,
|
||||
) -> Option<TokenStream> {
|
||||
match self {
|
||||
Self::Transparent(forward) => Some(forward.gen_enum_match_arm(variant, which_fn)),
|
||||
Self::Concrete(concrete) => f(concrete).or_else(|| {
|
||||
concrete
|
||||
.forward
|
||||
.as_ref()
|
||||
.map(|forward| forward.gen_enum_match_arm(variant, which_fn))
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DiagnosticConcreteArgs {
|
||||
pub code: Option<Code>,
|
||||
pub severity: Option<Severity>,
|
||||
pub help: Option<Help>,
|
||||
pub labels: Option<Labels>,
|
||||
pub source_code: Option<SourceCode>,
|
||||
pub url: Option<Url>,
|
||||
pub forward: Option<Forward>,
|
||||
pub related: Option<Related>,
|
||||
pub diagnostic_source: Option<DiagnosticSource>,
|
||||
}
|
||||
|
||||
impl DiagnosticConcreteArgs {
|
||||
fn for_fields(fields: &syn::Fields) -> Result<Self, syn::Error> {
|
||||
let labels = Labels::from_fields(fields)?;
|
||||
let source_code = SourceCode::from_fields(fields)?;
|
||||
let related = Related::from_fields(fields)?;
|
||||
let help = Help::from_fields(fields)?;
|
||||
let diagnostic_source = DiagnosticSource::from_fields(fields)?;
|
||||
Ok(DiagnosticConcreteArgs {
|
||||
code: None,
|
||||
help,
|
||||
related,
|
||||
severity: None,
|
||||
labels,
|
||||
url: None,
|
||||
forward: None,
|
||||
source_code,
|
||||
diagnostic_source,
|
||||
})
|
||||
}
|
||||
|
||||
fn add_args(
|
||||
&mut self,
|
||||
attr: &syn::Attribute,
|
||||
args: impl Iterator<Item = DiagnosticArg>,
|
||||
errors: &mut Vec<syn::Error>,
|
||||
) {
|
||||
for arg in args {
|
||||
match arg {
|
||||
DiagnosticArg::Transparent => {
|
||||
errors.push(syn::Error::new_spanned(attr, "transparent not allowed"));
|
||||
}
|
||||
DiagnosticArg::Forward(to_field) => {
|
||||
if self.forward.is_some() {
|
||||
errors.push(syn::Error::new_spanned(
|
||||
attr,
|
||||
"forward has already been specified",
|
||||
));
|
||||
}
|
||||
self.forward = Some(to_field);
|
||||
}
|
||||
DiagnosticArg::Code(new_code) => {
|
||||
if self.code.is_some() {
|
||||
errors.push(syn::Error::new_spanned(
|
||||
attr,
|
||||
"code has already been specified",
|
||||
));
|
||||
}
|
||||
self.code = Some(new_code);
|
||||
}
|
||||
DiagnosticArg::Severity(sev) => {
|
||||
if self.severity.is_some() {
|
||||
errors.push(syn::Error::new_spanned(
|
||||
attr,
|
||||
"severity has already been specified",
|
||||
));
|
||||
}
|
||||
self.severity = Some(sev);
|
||||
}
|
||||
DiagnosticArg::Help(hl) => {
|
||||
if self.help.is_some() {
|
||||
errors.push(syn::Error::new_spanned(
|
||||
attr,
|
||||
"help has already been specified",
|
||||
));
|
||||
}
|
||||
self.help = Some(hl);
|
||||
}
|
||||
DiagnosticArg::Url(u) => {
|
||||
if self.url.is_some() {
|
||||
errors.push(syn::Error::new_spanned(
|
||||
attr,
|
||||
"url has already been specified",
|
||||
));
|
||||
}
|
||||
self.url = Some(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DiagnosticDefArgs {
|
||||
fn parse(
|
||||
_ident: &syn::Ident,
|
||||
fields: &syn::Fields,
|
||||
attrs: &[&syn::Attribute],
|
||||
allow_transparent: bool,
|
||||
) -> syn::Result<Self> {
|
||||
let mut errors = Vec::new();
|
||||
|
||||
// Handle the only condition where Transparent is allowed
|
||||
if allow_transparent && attrs.len() == 1 {
|
||||
if let Ok(args) =
|
||||
attrs[0].parse_args_with(Punctuated::<DiagnosticArg, Token![,]>::parse_terminated)
|
||||
{
|
||||
if matches!(args.first(), Some(DiagnosticArg::Transparent)) {
|
||||
let forward = Forward::for_transparent_field(fields)?;
|
||||
return Ok(Self::Transparent(forward));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create errors for any appearances of Transparent
|
||||
let error_message = if allow_transparent {
|
||||
"diagnostic(transparent) not allowed in combination with other args"
|
||||
} else {
|
||||
"diagnostic(transparent) not allowed here"
|
||||
};
|
||||
fn is_transparent(d: &DiagnosticArg) -> bool {
|
||||
matches!(d, DiagnosticArg::Transparent)
|
||||
}
|
||||
|
||||
let mut concrete = DiagnosticConcreteArgs::for_fields(fields)?;
|
||||
for attr in attrs {
|
||||
let args =
|
||||
attr.parse_args_with(Punctuated::<DiagnosticArg, Token![,]>::parse_terminated);
|
||||
let args = match args {
|
||||
Ok(args) => args,
|
||||
Err(error) => {
|
||||
errors.push(error);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if args.iter().any(is_transparent) {
|
||||
errors.push(syn::Error::new_spanned(attr, error_message));
|
||||
}
|
||||
|
||||
let args = args
|
||||
.into_iter()
|
||||
.filter(|x| !matches!(x, DiagnosticArg::Transparent));
|
||||
|
||||
concrete.add_args(attr, args, &mut errors);
|
||||
}
|
||||
|
||||
let combined_error = errors.into_iter().reduce(|mut lhs, rhs| {
|
||||
lhs.combine(rhs);
|
||||
lhs
|
||||
});
|
||||
if let Some(error) = combined_error {
|
||||
Err(error)
|
||||
} else {
|
||||
Ok(DiagnosticDefArgs::Concrete(Box::new(concrete)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Diagnostic {
|
||||
pub fn from_derive_input(input: DeriveInput) -> Result<Self, syn::Error> {
|
||||
let input_attrs = input
|
||||
.attrs
|
||||
.iter()
|
||||
.filter(|x| x.path().is_ident("diagnostic"))
|
||||
.collect::<Vec<&syn::Attribute>>();
|
||||
Ok(match input.data {
|
||||
syn::Data::Struct(data_struct) => {
|
||||
let args = DiagnosticDefArgs::parse(
|
||||
&input.ident,
|
||||
&data_struct.fields,
|
||||
&input_attrs,
|
||||
true,
|
||||
)?;
|
||||
|
||||
Diagnostic::Struct {
|
||||
fields: data_struct.fields,
|
||||
ident: input.ident,
|
||||
generics: input.generics,
|
||||
args,
|
||||
}
|
||||
}
|
||||
syn::Data::Enum(syn::DataEnum { variants, .. }) => {
|
||||
let mut vars = Vec::new();
|
||||
for var in variants {
|
||||
let mut variant_attrs = input_attrs.clone();
|
||||
variant_attrs
|
||||
.extend(var.attrs.iter().filter(|x| x.path().is_ident("diagnostic")));
|
||||
let args =
|
||||
DiagnosticDefArgs::parse(&var.ident, &var.fields, &variant_attrs, true)?;
|
||||
vars.push(DiagnosticDef {
|
||||
ident: var.ident,
|
||||
fields: var.fields,
|
||||
args,
|
||||
});
|
||||
}
|
||||
Diagnostic::Enum {
|
||||
ident: input.ident,
|
||||
generics: input.generics,
|
||||
variants: vars,
|
||||
}
|
||||
}
|
||||
syn::Data::Union(_) => {
|
||||
return Err(syn::Error::new(
|
||||
input.ident.span(),
|
||||
"Can't derive Diagnostic for Unions",
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn gen(&self) -> TokenStream {
|
||||
match self {
|
||||
Self::Struct {
|
||||
ident,
|
||||
fields,
|
||||
generics,
|
||||
args,
|
||||
} => {
|
||||
let (impl_generics, ty_generics, where_clause) = &generics.split_for_impl();
|
||||
match args {
|
||||
DiagnosticDefArgs::Transparent(forward) => {
|
||||
let code_method = forward.gen_struct_method(WhichFn::Code);
|
||||
let help_method = forward.gen_struct_method(WhichFn::Help);
|
||||
let url_method = forward.gen_struct_method(WhichFn::Url);
|
||||
let labels_method = forward.gen_struct_method(WhichFn::Labels);
|
||||
let source_code_method = forward.gen_struct_method(WhichFn::SourceCode);
|
||||
let severity_method = forward.gen_struct_method(WhichFn::Severity);
|
||||
let related_method = forward.gen_struct_method(WhichFn::Related);
|
||||
let diagnostic_source_method =
|
||||
forward.gen_struct_method(WhichFn::DiagnosticSource);
|
||||
|
||||
quote! {
|
||||
impl #impl_generics miette::Diagnostic for #ident #ty_generics #where_clause {
|
||||
#code_method
|
||||
#help_method
|
||||
#url_method
|
||||
#labels_method
|
||||
#severity_method
|
||||
#source_code_method
|
||||
#related_method
|
||||
#diagnostic_source_method
|
||||
}
|
||||
}
|
||||
}
|
||||
DiagnosticDefArgs::Concrete(concrete) => {
|
||||
let forward = |which| {
|
||||
concrete
|
||||
.forward
|
||||
.as_ref()
|
||||
.map(|fwd| fwd.gen_struct_method(which))
|
||||
};
|
||||
let code_body = concrete
|
||||
.code
|
||||
.as_ref()
|
||||
.and_then(|x| x.gen_struct())
|
||||
.or_else(|| forward(WhichFn::Code));
|
||||
let help_body = concrete
|
||||
.help
|
||||
.as_ref()
|
||||
.and_then(|x| x.gen_struct(fields))
|
||||
.or_else(|| forward(WhichFn::Help));
|
||||
let sev_body = concrete
|
||||
.severity
|
||||
.as_ref()
|
||||
.and_then(|x| x.gen_struct())
|
||||
.or_else(|| forward(WhichFn::Severity));
|
||||
let rel_body = concrete
|
||||
.related
|
||||
.as_ref()
|
||||
.and_then(|x| x.gen_struct())
|
||||
.or_else(|| forward(WhichFn::Related));
|
||||
let url_body = concrete
|
||||
.url
|
||||
.as_ref()
|
||||
.and_then(|x| x.gen_struct(ident, fields))
|
||||
.or_else(|| forward(WhichFn::Url));
|
||||
let labels_body = concrete
|
||||
.labels
|
||||
.as_ref()
|
||||
.and_then(|x| x.gen_struct(fields))
|
||||
.or_else(|| forward(WhichFn::Labels));
|
||||
let src_body = concrete
|
||||
.source_code
|
||||
.as_ref()
|
||||
.and_then(|x| x.gen_struct(fields))
|
||||
.or_else(|| forward(WhichFn::SourceCode));
|
||||
let diagnostic_source = concrete
|
||||
.diagnostic_source
|
||||
.as_ref()
|
||||
.and_then(|x| x.gen_struct())
|
||||
.or_else(|| forward(WhichFn::DiagnosticSource));
|
||||
quote! {
|
||||
impl #impl_generics miette::Diagnostic for #ident #ty_generics #where_clause {
|
||||
#code_body
|
||||
#help_body
|
||||
#sev_body
|
||||
#rel_body
|
||||
#url_body
|
||||
#labels_body
|
||||
#src_body
|
||||
#diagnostic_source
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Self::Enum {
|
||||
ident,
|
||||
generics,
|
||||
variants,
|
||||
} => {
|
||||
let (impl_generics, ty_generics, where_clause) = &generics.split_for_impl();
|
||||
let code_body = Code::gen_enum(variants);
|
||||
let help_body = Help::gen_enum(variants);
|
||||
let sev_body = Severity::gen_enum(variants);
|
||||
let labels_body = Labels::gen_enum(variants);
|
||||
let src_body = SourceCode::gen_enum(variants);
|
||||
let rel_body = Related::gen_enum(variants);
|
||||
let url_body = Url::gen_enum(ident, variants);
|
||||
let diagnostic_source_body = DiagnosticSource::gen_enum(variants);
|
||||
quote! {
|
||||
impl #impl_generics miette::Diagnostic for #ident #ty_generics #where_clause {
|
||||
#code_body
|
||||
#help_body
|
||||
#sev_body
|
||||
#labels_body
|
||||
#src_body
|
||||
#rel_body
|
||||
#url_body
|
||||
#diagnostic_source_body
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
42
vendor/miette-derive/src/diagnostic_arg.rs
vendored
Normal file
42
vendor/miette-derive/src/diagnostic_arg.rs
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
|
||||
use crate::code::Code;
|
||||
use crate::forward::Forward;
|
||||
use crate::help::Help;
|
||||
use crate::severity::Severity;
|
||||
use crate::url::Url;
|
||||
|
||||
pub enum DiagnosticArg {
|
||||
Transparent,
|
||||
Code(Code),
|
||||
Severity(Severity),
|
||||
Help(Help),
|
||||
Url(Url),
|
||||
Forward(Forward),
|
||||
}
|
||||
|
||||
impl Parse for DiagnosticArg {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let ident = input.fork().parse::<syn::Ident>()?;
|
||||
if ident == "transparent" {
|
||||
// consume the token
|
||||
let _: syn::Ident = input.parse()?;
|
||||
Ok(DiagnosticArg::Transparent)
|
||||
} else if ident == "forward" {
|
||||
Ok(DiagnosticArg::Forward(input.parse()?))
|
||||
} else if ident == "code" {
|
||||
Ok(DiagnosticArg::Code(input.parse()?))
|
||||
} else if ident == "severity" {
|
||||
Ok(DiagnosticArg::Severity(input.parse()?))
|
||||
} else if ident == "help" {
|
||||
Ok(DiagnosticArg::Help(input.parse()?))
|
||||
} else if ident == "url" {
|
||||
Ok(DiagnosticArg::Url(input.parse()?))
|
||||
} else {
|
||||
Err(syn::Error::new(
|
||||
ident.span(),
|
||||
"Unrecognized diagnostic option",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
78
vendor/miette-derive/src/diagnostic_source.rs
vendored
Normal file
78
vendor/miette-derive/src/diagnostic_source.rs
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
use crate::forward::WhichFn;
|
||||
use crate::{
|
||||
diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
|
||||
utils::{display_pat_members, gen_all_variants_with},
|
||||
};
|
||||
|
||||
pub struct DiagnosticSource(syn::Member);
|
||||
|
||||
impl DiagnosticSource {
|
||||
pub(crate) fn from_fields(fields: &syn::Fields) -> syn::Result<Option<Self>> {
|
||||
match fields {
|
||||
syn::Fields::Named(named) => Self::from_fields_vec(named.named.iter().collect()),
|
||||
syn::Fields::Unnamed(unnamed) => {
|
||||
Self::from_fields_vec(unnamed.unnamed.iter().collect())
|
||||
}
|
||||
syn::Fields::Unit => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_fields_vec(fields: Vec<&syn::Field>) -> syn::Result<Option<Self>> {
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
for attr in &field.attrs {
|
||||
if attr.path().is_ident("diagnostic_source") {
|
||||
let diagnostic_source = if let Some(ident) = field.ident.clone() {
|
||||
syn::Member::Named(ident)
|
||||
} else {
|
||||
syn::Member::Unnamed(syn::Index {
|
||||
index: i as u32,
|
||||
span: field.span(),
|
||||
})
|
||||
};
|
||||
return Ok(Some(DiagnosticSource(diagnostic_source)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub(crate) fn gen_enum(variants: &[DiagnosticDef]) -> Option<TokenStream> {
|
||||
gen_all_variants_with(
|
||||
variants,
|
||||
WhichFn::DiagnosticSource,
|
||||
|ident,
|
||||
fields,
|
||||
DiagnosticConcreteArgs {
|
||||
diagnostic_source, ..
|
||||
}| {
|
||||
let (display_pat, _display_members) = display_pat_members(fields);
|
||||
diagnostic_source.as_ref().map(|diagnostic_source| {
|
||||
let rel = match &diagnostic_source.0 {
|
||||
syn::Member::Named(ident) => ident.clone(),
|
||||
syn::Member::Unnamed(syn::Index { index, .. }) => {
|
||||
quote::format_ident!("_{}", index)
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
Self::#ident #display_pat => {
|
||||
std::option::Option::Some(std::borrow::Borrow::borrow(#rel))
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn gen_struct(&self) -> Option<TokenStream> {
|
||||
let rel = &self.0;
|
||||
Some(quote! {
|
||||
fn diagnostic_source<'a>(&'a self) -> std::option::Option<&'a dyn miette::Diagnostic> {
|
||||
std::option::Option::Some(std::borrow::Borrow::borrow(&self.#rel))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
235
vendor/miette-derive/src/fmt.rs
vendored
Normal file
235
vendor/miette-derive/src/fmt.rs
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
// NOTE: Most code in this file is taken straight from `thiserror`.
|
||||
use std::collections::HashSet as Set;
|
||||
use std::iter::FromIterator;
|
||||
|
||||
use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
|
||||
use quote::{format_ident, quote, quote_spanned, ToTokens};
|
||||
use syn::ext::IdentExt;
|
||||
use syn::parse::{ParseStream, Parser};
|
||||
use syn::{braced, bracketed, parenthesized, Ident, Index, LitStr, Member, Result, Token};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Display {
|
||||
pub fmt: LitStr,
|
||||
pub args: TokenStream,
|
||||
pub has_bonus_display: bool,
|
||||
}
|
||||
|
||||
impl ToTokens for Display {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let fmt = &self.fmt;
|
||||
let args = &self.args;
|
||||
tokens.extend(quote! {
|
||||
write!(__formatter, #fmt #args)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Display {
|
||||
// Transform `"error {var}"` to `"error {}", var`.
|
||||
pub fn expand_shorthand(&mut self, members: &Set<Member>) {
|
||||
let raw_args = self.args.clone();
|
||||
let mut named_args = explicit_named_args.parse2(raw_args).unwrap();
|
||||
|
||||
let span = self.fmt.span();
|
||||
let fmt = self.fmt.value();
|
||||
let mut read = fmt.as_str();
|
||||
let mut out = String::new();
|
||||
let mut args = self.args.clone();
|
||||
let mut has_bonus_display = false;
|
||||
|
||||
let mut has_trailing_comma = false;
|
||||
if let Some(TokenTree::Punct(punct)) = args.clone().into_iter().last() {
|
||||
if punct.as_char() == ',' {
|
||||
has_trailing_comma = true;
|
||||
}
|
||||
}
|
||||
|
||||
while let Some(brace) = read.find('{') {
|
||||
out += &read[..brace + 1];
|
||||
read = &read[brace + 1..];
|
||||
if read.starts_with('{') {
|
||||
out.push('{');
|
||||
read = &read[1..];
|
||||
continue;
|
||||
}
|
||||
let next = match read.chars().next() {
|
||||
Some(next) => next,
|
||||
None => return,
|
||||
};
|
||||
let member = match next {
|
||||
'0'..='9' => {
|
||||
let int = take_int(&mut read);
|
||||
let member = match int.parse::<u32>() {
|
||||
Ok(index) => Member::Unnamed(Index { index, span }),
|
||||
Err(_) => return,
|
||||
};
|
||||
if !members.contains(&member) {
|
||||
out += ∫
|
||||
continue;
|
||||
}
|
||||
member
|
||||
}
|
||||
'a'..='z' | 'A'..='Z' | '_' => {
|
||||
let mut ident = take_ident(&mut read);
|
||||
ident.set_span(span);
|
||||
Member::Named(ident)
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
let local = match &member {
|
||||
Member::Unnamed(index) => format_ident!("_{}", index),
|
||||
Member::Named(ident) => ident.clone(),
|
||||
};
|
||||
let mut formatvar = local.clone();
|
||||
if formatvar.to_string().starts_with("r#") {
|
||||
formatvar = format_ident!("r_{}", formatvar);
|
||||
}
|
||||
if formatvar.to_string().starts_with('_') {
|
||||
// Work around leading underscore being rejected by 1.40 and
|
||||
// older compilers. https://github.com/rust-lang/rust/pull/66847
|
||||
formatvar = format_ident!("field_{}", formatvar);
|
||||
}
|
||||
out += &formatvar.to_string();
|
||||
if !named_args.insert(formatvar.clone()) {
|
||||
// Already specified in the format argument list.
|
||||
continue;
|
||||
}
|
||||
if !has_trailing_comma {
|
||||
args.extend(quote_spanned!(span=> ,));
|
||||
}
|
||||
args.extend(quote_spanned!(span=> #formatvar = #local));
|
||||
if read.starts_with('}') && members.contains(&member) {
|
||||
has_bonus_display = true;
|
||||
// args.extend(quote_spanned!(span=> .as_display()));
|
||||
}
|
||||
has_trailing_comma = false;
|
||||
}
|
||||
|
||||
out += read;
|
||||
self.fmt = LitStr::new(&out, self.fmt.span());
|
||||
self.args = args;
|
||||
self.has_bonus_display = has_bonus_display;
|
||||
}
|
||||
}
|
||||
|
||||
fn explicit_named_args(input: ParseStream) -> Result<Set<Ident>> {
|
||||
let mut named_args = Set::new();
|
||||
|
||||
while !input.is_empty() {
|
||||
if input.peek(Token![,]) && input.peek2(Ident::peek_any) && input.peek3(Token![=]) {
|
||||
input.parse::<Token![,]>()?;
|
||||
let ident = input.call(Ident::parse_any)?;
|
||||
input.parse::<Token![=]>()?;
|
||||
named_args.insert(ident);
|
||||
} else {
|
||||
input.parse::<TokenTree>()?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(named_args)
|
||||
}
|
||||
|
||||
fn take_int(read: &mut &str) -> String {
|
||||
let mut int = String::new();
|
||||
for (i, ch) in read.char_indices() {
|
||||
match ch {
|
||||
'0'..='9' => int.push(ch),
|
||||
_ => {
|
||||
*read = &read[i..];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
int
|
||||
}
|
||||
|
||||
fn take_ident(read: &mut &str) -> Ident {
|
||||
let mut ident = String::new();
|
||||
let raw = read.starts_with("r#");
|
||||
if raw {
|
||||
ident.push_str("r#");
|
||||
*read = &read[2..];
|
||||
}
|
||||
for (i, ch) in read.char_indices() {
|
||||
match ch {
|
||||
'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => ident.push(ch),
|
||||
_ => {
|
||||
*read = &read[i..];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ident::parse_any.parse_str(&ident).unwrap()
|
||||
}
|
||||
|
||||
pub fn parse_token_expr(input: ParseStream, mut begin_expr: bool) -> Result<TokenStream> {
|
||||
let mut tokens = Vec::new();
|
||||
while !input.is_empty() {
|
||||
if begin_expr && input.peek(Token![.]) {
|
||||
if input.peek2(Ident) {
|
||||
input.parse::<Token![.]>()?;
|
||||
begin_expr = false;
|
||||
continue;
|
||||
}
|
||||
if input.peek2(syn::LitInt) {
|
||||
input.parse::<Token![.]>()?;
|
||||
let int: Index = input.parse()?;
|
||||
let ident = format_ident!("_{}", int.index, span = int.span);
|
||||
tokens.push(TokenTree::Ident(ident));
|
||||
begin_expr = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
begin_expr = input.peek(Token![break])
|
||||
|| input.peek(Token![continue])
|
||||
|| input.peek(Token![if])
|
||||
|| input.peek(Token![in])
|
||||
|| input.peek(Token![match])
|
||||
|| input.peek(Token![mut])
|
||||
|| input.peek(Token![return])
|
||||
|| input.peek(Token![while])
|
||||
|| input.peek(Token![+])
|
||||
|| input.peek(Token![&])
|
||||
|| input.peek(Token![!])
|
||||
|| input.peek(Token![^])
|
||||
|| input.peek(Token![,])
|
||||
|| input.peek(Token![/])
|
||||
|| input.peek(Token![=])
|
||||
|| input.peek(Token![>])
|
||||
|| input.peek(Token![<])
|
||||
|| input.peek(Token![|])
|
||||
|| input.peek(Token![%])
|
||||
|| input.peek(Token![;])
|
||||
|| input.peek(Token![*])
|
||||
|| input.peek(Token![-]);
|
||||
|
||||
let token: TokenTree = if input.peek(syn::token::Paren) {
|
||||
let content;
|
||||
let delimiter = parenthesized!(content in input);
|
||||
let nested = parse_token_expr(&content, true)?;
|
||||
let mut group = Group::new(Delimiter::Parenthesis, nested);
|
||||
group.set_span(delimiter.span.join());
|
||||
TokenTree::Group(group)
|
||||
} else if input.peek(syn::token::Brace) {
|
||||
let content;
|
||||
let delimiter = braced!(content in input);
|
||||
let nested = parse_token_expr(&content, true)?;
|
||||
let mut group = Group::new(Delimiter::Brace, nested);
|
||||
group.set_span(delimiter.span.join());
|
||||
TokenTree::Group(group)
|
||||
} else if input.peek(syn::token::Bracket) {
|
||||
let content;
|
||||
let delimiter = bracketed!(content in input);
|
||||
let nested = parse_token_expr(&content, true)?;
|
||||
let mut group = Group::new(Delimiter::Bracket, nested);
|
||||
group.set_span(delimiter.span.join());
|
||||
TokenTree::Group(group)
|
||||
} else {
|
||||
input.parse()?
|
||||
};
|
||||
tokens.push(token);
|
||||
}
|
||||
Ok(TokenStream::from_iter(tokens))
|
||||
}
|
161
vendor/miette-derive/src/forward.rs
vendored
Normal file
161
vendor/miette-derive/src/forward.rs
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{
|
||||
parenthesized,
|
||||
parse::{Parse, ParseStream},
|
||||
spanned::Spanned,
|
||||
};
|
||||
|
||||
pub enum Forward {
|
||||
Unnamed(usize),
|
||||
Named(syn::Ident),
|
||||
}
|
||||
|
||||
impl Parse for Forward {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let forward = input.parse::<syn::Ident>()?;
|
||||
if forward != "forward" {
|
||||
return Err(syn::Error::new(forward.span(), "msg"));
|
||||
}
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
let looky = content.lookahead1();
|
||||
if looky.peek(syn::LitInt) {
|
||||
let int: syn::LitInt = content.parse()?;
|
||||
let index = int.base10_parse()?;
|
||||
return Ok(Forward::Unnamed(index));
|
||||
}
|
||||
Ok(Forward::Named(content.parse()?))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum WhichFn {
|
||||
Code,
|
||||
Help,
|
||||
Url,
|
||||
Severity,
|
||||
Labels,
|
||||
SourceCode,
|
||||
Related,
|
||||
DiagnosticSource,
|
||||
}
|
||||
|
||||
impl WhichFn {
|
||||
pub fn method_call(&self) -> TokenStream {
|
||||
match self {
|
||||
Self::Code => quote! { code() },
|
||||
Self::Help => quote! { help() },
|
||||
Self::Url => quote! { url() },
|
||||
Self::Severity => quote! { severity() },
|
||||
Self::Labels => quote! { labels() },
|
||||
Self::SourceCode => quote! { source_code() },
|
||||
Self::Related => quote! { related() },
|
||||
Self::DiagnosticSource => quote! { diagnostic_source() },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signature(&self) -> TokenStream {
|
||||
match self {
|
||||
Self::Code => quote! {
|
||||
fn code(& self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>>
|
||||
},
|
||||
Self::Help => quote! {
|
||||
fn help(& self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>>
|
||||
},
|
||||
Self::Url => quote! {
|
||||
fn url(& self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>>
|
||||
},
|
||||
Self::Severity => quote! {
|
||||
fn severity(&self) -> std::option::Option<miette::Severity>
|
||||
},
|
||||
Self::Related => quote! {
|
||||
fn related(&self) -> std::option::Option<std::boxed::Box<dyn std::iter::Iterator<Item = &dyn miette::Diagnostic> + '_>>
|
||||
},
|
||||
Self::Labels => quote! {
|
||||
fn labels(&self) -> std::option::Option<std::boxed::Box<dyn std::iter::Iterator<Item = miette::LabeledSpan> + '_>>
|
||||
},
|
||||
Self::SourceCode => quote! {
|
||||
fn source_code(&self) -> std::option::Option<&dyn miette::SourceCode>
|
||||
},
|
||||
Self::DiagnosticSource => quote! {
|
||||
fn diagnostic_source(&self) -> std::option::Option<&dyn miette::Diagnostic>
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn catchall_arm(&self) -> TokenStream {
|
||||
quote! { _ => std::option::Option::None }
|
||||
}
|
||||
}
|
||||
|
||||
impl Forward {
|
||||
pub fn for_transparent_field(fields: &syn::Fields) -> syn::Result<Self> {
|
||||
let make_err = || {
|
||||
syn::Error::new(
|
||||
fields.span(),
|
||||
"you can only use #[diagnostic(transparent)] with exactly one field",
|
||||
)
|
||||
};
|
||||
match fields {
|
||||
syn::Fields::Named(named) => {
|
||||
let mut iter = named.named.iter();
|
||||
let field = iter.next().ok_or_else(make_err)?;
|
||||
if iter.next().is_some() {
|
||||
return Err(make_err());
|
||||
}
|
||||
let field_name = field
|
||||
.ident
|
||||
.clone()
|
||||
.unwrap_or_else(|| format_ident!("unnamed"));
|
||||
Ok(Self::Named(field_name))
|
||||
}
|
||||
syn::Fields::Unnamed(unnamed) => {
|
||||
if unnamed.unnamed.iter().len() != 1 {
|
||||
return Err(make_err());
|
||||
}
|
||||
Ok(Self::Unnamed(0))
|
||||
}
|
||||
_ => Err(syn::Error::new(
|
||||
fields.span(),
|
||||
"you cannot use #[diagnostic(transparent)] with a unit struct or a unit variant",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_struct_method(&self, which_fn: WhichFn) -> TokenStream {
|
||||
let signature = which_fn.signature();
|
||||
let method_call = which_fn.method_call();
|
||||
|
||||
let field_name = match self {
|
||||
Forward::Named(field_name) => quote!(#field_name),
|
||||
Forward::Unnamed(index) => {
|
||||
let index = syn::Index::from(*index);
|
||||
quote!(#index)
|
||||
}
|
||||
};
|
||||
|
||||
quote! {
|
||||
#[inline]
|
||||
#signature {
|
||||
self.#field_name.#method_call
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_enum_match_arm(&self, variant: &syn::Ident, which_fn: WhichFn) -> TokenStream {
|
||||
let method_call = which_fn.method_call();
|
||||
match self {
|
||||
Forward::Named(field_name) => quote! {
|
||||
Self::#variant { #field_name, .. } => #field_name.#method_call,
|
||||
},
|
||||
Forward::Unnamed(index) => {
|
||||
let underscores: Vec<_> = core::iter::repeat(quote! { _, }).take(*index).collect();
|
||||
let unnamed = format_ident!("unnamed");
|
||||
quote! {
|
||||
Self::#variant ( #(#underscores)* #unnamed, .. ) => #unnamed.#method_call,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
146
vendor/miette-derive/src/help.rs
vendored
Normal file
146
vendor/miette-derive/src/help.rs
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{
|
||||
parenthesized,
|
||||
parse::{Parse, ParseStream},
|
||||
spanned::Spanned,
|
||||
Fields, Token,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
|
||||
utils::{display_pat_members, gen_all_variants_with},
|
||||
};
|
||||
use crate::{
|
||||
fmt::{self, Display},
|
||||
forward::WhichFn,
|
||||
};
|
||||
|
||||
pub enum Help {
|
||||
Display(Display),
|
||||
Field(syn::Member, Box<syn::Type>),
|
||||
}
|
||||
|
||||
impl Parse for Help {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let ident = input.parse::<syn::Ident>()?;
|
||||
if ident == "help" {
|
||||
let la = input.lookahead1();
|
||||
if la.peek(syn::token::Paren) {
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
let fmt = content.parse()?;
|
||||
let args = if content.is_empty() {
|
||||
TokenStream::new()
|
||||
} else {
|
||||
fmt::parse_token_expr(&content, false)?
|
||||
};
|
||||
let display = Display {
|
||||
fmt,
|
||||
args,
|
||||
has_bonus_display: false,
|
||||
};
|
||||
Ok(Help::Display(display))
|
||||
} else {
|
||||
input.parse::<Token![=]>()?;
|
||||
Ok(Help::Display(Display {
|
||||
fmt: input.parse()?,
|
||||
args: TokenStream::new(),
|
||||
has_bonus_display: false,
|
||||
}))
|
||||
}
|
||||
} else {
|
||||
Err(syn::Error::new(ident.span(), "not a help"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Help {
|
||||
pub(crate) fn from_fields(fields: &syn::Fields) -> syn::Result<Option<Self>> {
|
||||
match fields {
|
||||
syn::Fields::Named(named) => Self::from_fields_vec(named.named.iter().collect()),
|
||||
syn::Fields::Unnamed(unnamed) => {
|
||||
Self::from_fields_vec(unnamed.unnamed.iter().collect())
|
||||
}
|
||||
syn::Fields::Unit => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_fields_vec(fields: Vec<&syn::Field>) -> syn::Result<Option<Self>> {
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
for attr in &field.attrs {
|
||||
if attr.path().is_ident("help") {
|
||||
let help = if let Some(ident) = field.ident.clone() {
|
||||
syn::Member::Named(ident)
|
||||
} else {
|
||||
syn::Member::Unnamed(syn::Index {
|
||||
index: i as u32,
|
||||
span: field.span(),
|
||||
})
|
||||
};
|
||||
return Ok(Some(Help::Field(help, Box::new(field.ty.clone()))));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
pub(crate) fn gen_enum(variants: &[DiagnosticDef]) -> Option<TokenStream> {
|
||||
gen_all_variants_with(
|
||||
variants,
|
||||
WhichFn::Help,
|
||||
|ident, fields, DiagnosticConcreteArgs { help, .. }| {
|
||||
let (display_pat, display_members) = display_pat_members(fields);
|
||||
match &help.as_ref()? {
|
||||
Help::Display(display) => {
|
||||
let (fmt, args) = display.expand_shorthand_cloned(&display_members);
|
||||
Some(quote! {
|
||||
Self::#ident #display_pat => std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args))),
|
||||
})
|
||||
}
|
||||
Help::Field(member, ty) => {
|
||||
let help = match &member {
|
||||
syn::Member::Named(ident) => ident.clone(),
|
||||
syn::Member::Unnamed(syn::Index { index, .. }) => {
|
||||
format_ident!("_{}", index)
|
||||
}
|
||||
};
|
||||
let var = quote! { __miette_internal_var };
|
||||
Some(quote! {
|
||||
Self::#ident #display_pat => {
|
||||
use miette::macro_helpers::ToOption;
|
||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(&#help).as_ref().map(|#var| -> std::boxed::Box<dyn std::fmt::Display + '_> { std::boxed::Box::new(format!("{}", #var)) })
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn gen_struct(&self, fields: &Fields) -> Option<TokenStream> {
|
||||
let (display_pat, display_members) = display_pat_members(fields);
|
||||
match self {
|
||||
Help::Display(display) => {
|
||||
let (fmt, args) = display.expand_shorthand_cloned(&display_members);
|
||||
Some(quote! {
|
||||
fn help(&self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>> {
|
||||
#[allow(unused_variables, deprecated)]
|
||||
let Self #display_pat = self;
|
||||
std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args)))
|
||||
}
|
||||
})
|
||||
}
|
||||
Help::Field(member, ty) => {
|
||||
let var = quote! { __miette_internal_var };
|
||||
Some(quote! {
|
||||
fn help(&self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>> {
|
||||
#[allow(unused_variables, deprecated)]
|
||||
let Self #display_pat = self;
|
||||
use miette::macro_helpers::ToOption;
|
||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(&self.#member).as_ref().map(|#var| -> std::boxed::Box<dyn std::fmt::Display + '_> { std::boxed::Box::new(format!("{}", #var)) })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
207
vendor/miette-derive/src/label.rs
vendored
Normal file
207
vendor/miette-derive/src/label.rs
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{
|
||||
parenthesized,
|
||||
parse::{Parse, ParseStream},
|
||||
spanned::Spanned,
|
||||
Token,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
|
||||
fmt::{self, Display},
|
||||
forward::WhichFn,
|
||||
utils::{display_pat_members, gen_all_variants_with},
|
||||
};
|
||||
|
||||
pub struct Labels(Vec<Label>);
|
||||
|
||||
struct Label {
|
||||
label: Option<Display>,
|
||||
ty: syn::Type,
|
||||
span: syn::Member,
|
||||
}
|
||||
|
||||
struct LabelAttr {
|
||||
label: Option<Display>,
|
||||
}
|
||||
|
||||
impl Parse for LabelAttr {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
// Skip a token.
|
||||
// This should receive one of:
|
||||
// - label = "..."
|
||||
// - label("...")
|
||||
let _ = input.step(|cursor| {
|
||||
if let Some((_, next)) = cursor.token_tree() {
|
||||
Ok(((), next))
|
||||
} else {
|
||||
Err(cursor.error("unexpected empty attribute"))
|
||||
}
|
||||
});
|
||||
let la = input.lookahead1();
|
||||
let label = if la.peek(syn::token::Paren) {
|
||||
// #[label("{}", x)]
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
if content.peek(syn::LitStr) {
|
||||
let fmt = content.parse()?;
|
||||
let args = if content.is_empty() {
|
||||
TokenStream::new()
|
||||
} else {
|
||||
fmt::parse_token_expr(&content, false)?
|
||||
};
|
||||
let display = Display {
|
||||
fmt,
|
||||
args,
|
||||
has_bonus_display: false,
|
||||
};
|
||||
Some(display)
|
||||
} else {
|
||||
return Err(syn::Error::new(input.span(), "Invalid argument to label() attribute. The first argument must be a literal string."));
|
||||
}
|
||||
} else if la.peek(Token![=]) {
|
||||
// #[label = "blabla"]
|
||||
input.parse::<Token![=]>()?;
|
||||
Some(Display {
|
||||
fmt: input.parse()?,
|
||||
args: TokenStream::new(),
|
||||
has_bonus_display: false,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ok(LabelAttr { label })
|
||||
}
|
||||
}
|
||||
|
||||
impl Labels {
|
||||
pub fn from_fields(fields: &syn::Fields) -> syn::Result<Option<Self>> {
|
||||
match fields {
|
||||
syn::Fields::Named(named) => Self::from_fields_vec(named.named.iter().collect()),
|
||||
syn::Fields::Unnamed(unnamed) => {
|
||||
Self::from_fields_vec(unnamed.unnamed.iter().collect())
|
||||
}
|
||||
syn::Fields::Unit => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_fields_vec(fields: Vec<&syn::Field>) -> syn::Result<Option<Self>> {
|
||||
let mut labels = Vec::new();
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
for attr in &field.attrs {
|
||||
if attr.path().is_ident("label") {
|
||||
let span = if let Some(ident) = field.ident.clone() {
|
||||
syn::Member::Named(ident)
|
||||
} else {
|
||||
syn::Member::Unnamed(syn::Index {
|
||||
index: i as u32,
|
||||
span: field.span(),
|
||||
})
|
||||
};
|
||||
use quote::ToTokens;
|
||||
let LabelAttr { label } =
|
||||
syn::parse2::<LabelAttr>(attr.meta.to_token_stream())?;
|
||||
labels.push(Label {
|
||||
label,
|
||||
span,
|
||||
ty: field.ty.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if labels.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(Labels(labels)))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn gen_struct(&self, fields: &syn::Fields) -> Option<TokenStream> {
|
||||
let (display_pat, display_members) = display_pat_members(fields);
|
||||
let labels = self.0.iter().map(|highlight| {
|
||||
let Label { span, label, ty } = highlight;
|
||||
let var = quote! { __miette_internal_var };
|
||||
if let Some(display) = label {
|
||||
let (fmt, args) = display.expand_shorthand_cloned(&display_members);
|
||||
quote! {
|
||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(&self.#span)
|
||||
.map(|#var| miette::LabeledSpan::new_with_span(
|
||||
std::option::Option::Some(format!(#fmt #args)),
|
||||
#var.clone(),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(&self.#span)
|
||||
.map(|#var| miette::LabeledSpan::new_with_span(
|
||||
std::option::Option::None,
|
||||
#var.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
});
|
||||
Some(quote! {
|
||||
#[allow(unused_variables)]
|
||||
fn labels(&self) -> std::option::Option<std::boxed::Box<dyn std::iter::Iterator<Item = miette::LabeledSpan> + '_>> {
|
||||
use miette::macro_helpers::ToOption;
|
||||
let Self #display_pat = self;
|
||||
std::option::Option::Some(Box::new(vec![
|
||||
#(#labels),*
|
||||
].into_iter().filter(Option::is_some).map(Option::unwrap)))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn gen_enum(variants: &[DiagnosticDef]) -> Option<TokenStream> {
|
||||
gen_all_variants_with(
|
||||
variants,
|
||||
WhichFn::Labels,
|
||||
|ident, fields, DiagnosticConcreteArgs { labels, .. }| {
|
||||
let (display_pat, display_members) = display_pat_members(fields);
|
||||
labels.as_ref().and_then(|labels| {
|
||||
let variant_labels = labels.0.iter().map(|label| {
|
||||
let Label { span, label, ty } = label;
|
||||
let field = match &span {
|
||||
syn::Member::Named(ident) => ident.clone(),
|
||||
syn::Member::Unnamed(syn::Index { index, .. }) => {
|
||||
format_ident!("_{}", index)
|
||||
}
|
||||
};
|
||||
let var = quote! { __miette_internal_var };
|
||||
if let Some(display) = label {
|
||||
let (fmt, args) = display.expand_shorthand_cloned(&display_members);
|
||||
quote! {
|
||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(#field)
|
||||
.map(|#var| miette::LabeledSpan::new_with_span(
|
||||
std::option::Option::Some(format!(#fmt #args)),
|
||||
#var.clone(),
|
||||
))
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
miette::macro_helpers::OptionalWrapper::<#ty>::new().to_option(#field)
|
||||
.map(|#var| miette::LabeledSpan::new_with_span(
|
||||
std::option::Option::None,
|
||||
#var.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
});
|
||||
let variant_name = ident.clone();
|
||||
match &fields {
|
||||
syn::Fields::Unit => None,
|
||||
_ => Some(quote! {
|
||||
Self::#variant_name #display_pat => {
|
||||
use miette::macro_helpers::ToOption;
|
||||
std::option::Option::Some(std::boxed::Box::new(vec![
|
||||
#(#variant_labels),*
|
||||
].into_iter().filter(Option::is_some).map(Option::unwrap)))
|
||||
}
|
||||
}),
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
32
vendor/miette-derive/src/lib.rs
vendored
Normal file
32
vendor/miette-derive/src/lib.rs
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
|
||||
use diagnostic::Diagnostic;
|
||||
|
||||
mod code;
|
||||
mod diagnostic;
|
||||
mod diagnostic_arg;
|
||||
mod diagnostic_source;
|
||||
mod fmt;
|
||||
mod forward;
|
||||
mod help;
|
||||
mod label;
|
||||
mod related;
|
||||
mod severity;
|
||||
mod source_code;
|
||||
mod url;
|
||||
mod utils;
|
||||
|
||||
#[proc_macro_derive(
|
||||
Diagnostic,
|
||||
attributes(diagnostic, source_code, label, related, help, diagnostic_source)
|
||||
)]
|
||||
pub fn derive_diagnostic(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
let cmd = match Diagnostic::from_derive_input(input) {
|
||||
Ok(cmd) => cmd.gen(),
|
||||
Err(err) => return err.to_compile_error().into(),
|
||||
};
|
||||
// panic!("{:#}", cmd.to_token_stream());
|
||||
quote!(#cmd).into()
|
||||
}
|
79
vendor/miette-derive/src/related.rs
vendored
Normal file
79
vendor/miette-derive/src/related.rs
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
use crate::{
|
||||
diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
|
||||
forward::WhichFn,
|
||||
utils::{display_pat_members, gen_all_variants_with},
|
||||
};
|
||||
|
||||
pub struct Related(syn::Member);
|
||||
|
||||
impl Related {
|
||||
pub(crate) fn from_fields(fields: &syn::Fields) -> syn::Result<Option<Self>> {
|
||||
match fields {
|
||||
syn::Fields::Named(named) => Self::from_fields_vec(named.named.iter().collect()),
|
||||
syn::Fields::Unnamed(unnamed) => {
|
||||
Self::from_fields_vec(unnamed.unnamed.iter().collect())
|
||||
}
|
||||
syn::Fields::Unit => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_fields_vec(fields: Vec<&syn::Field>) -> syn::Result<Option<Self>> {
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
for attr in &field.attrs {
|
||||
if attr.path().is_ident("related") {
|
||||
let related = if let Some(ident) = field.ident.clone() {
|
||||
syn::Member::Named(ident)
|
||||
} else {
|
||||
syn::Member::Unnamed(syn::Index {
|
||||
index: i as u32,
|
||||
span: field.span(),
|
||||
})
|
||||
};
|
||||
return Ok(Some(Related(related)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub(crate) fn gen_enum(variants: &[DiagnosticDef]) -> Option<TokenStream> {
|
||||
gen_all_variants_with(
|
||||
variants,
|
||||
WhichFn::Related,
|
||||
|ident, fields, DiagnosticConcreteArgs { related, .. }| {
|
||||
let (display_pat, _display_members) = display_pat_members(fields);
|
||||
related.as_ref().map(|related| {
|
||||
let rel = match &related.0 {
|
||||
syn::Member::Named(ident) => ident.clone(),
|
||||
syn::Member::Unnamed(syn::Index { index, .. }) => {
|
||||
format_ident!("_{}", index)
|
||||
}
|
||||
};
|
||||
quote! {
|
||||
Self::#ident #display_pat => {
|
||||
std::option::Option::Some(std::boxed::Box::new(
|
||||
#rel.iter().map(|x| -> &(dyn miette::Diagnostic) { &*x })
|
||||
))
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn gen_struct(&self) -> Option<TokenStream> {
|
||||
let rel = &self.0;
|
||||
Some(quote! {
|
||||
fn related<'a>(&'a self) -> std::option::Option<std::boxed::Box<dyn std::iter::Iterator<Item = &'a dyn miette::Diagnostic> + 'a>> {
|
||||
use ::core::borrow::Borrow;
|
||||
std::option::Option::Some(std::boxed::Box::new(
|
||||
self.#rel.iter().map(|x| -> &(dyn miette::Diagnostic) { &*x.borrow() })
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
89
vendor/miette-derive/src/severity.rs
vendored
Normal file
89
vendor/miette-derive/src/severity.rs
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
parenthesized,
|
||||
parse::{Parse, ParseStream},
|
||||
Token,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
|
||||
forward::WhichFn,
|
||||
utils::gen_all_variants_with,
|
||||
};
|
||||
|
||||
pub struct Severity(pub syn::Ident);
|
||||
|
||||
impl Parse for Severity {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let ident = input.parse::<syn::Ident>()?;
|
||||
if ident == "severity" {
|
||||
let la = input.lookahead1();
|
||||
if la.peek(syn::token::Paren) {
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
let la = content.lookahead1();
|
||||
if la.peek(syn::LitStr) {
|
||||
let str = content.parse::<syn::LitStr>()?;
|
||||
let sev = get_severity(&str.value(), str.span())?;
|
||||
Ok(Severity(syn::Ident::new(&sev, str.span())))
|
||||
} else {
|
||||
let ident = content.parse::<syn::Ident>()?;
|
||||
let sev = get_severity(&ident.to_string(), ident.span())?;
|
||||
Ok(Severity(syn::Ident::new(&sev, ident.span())))
|
||||
}
|
||||
} else {
|
||||
input.parse::<Token![=]>()?;
|
||||
let str = input.parse::<syn::LitStr>()?;
|
||||
let sev = get_severity(&str.value(), str.span())?;
|
||||
Ok(Severity(syn::Ident::new(&sev, str.span())))
|
||||
}
|
||||
} else {
|
||||
Err(syn::Error::new(
|
||||
ident.span(),
|
||||
"MIETTE BUG: not a severity option",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_severity(input: &str, span: Span) -> syn::Result<String> {
|
||||
match input.to_lowercase().as_ref() {
|
||||
"error" | "err" => Ok("Error".into()),
|
||||
"warning" | "warn" => Ok("Warning".into()),
|
||||
"advice" | "adv" | "info" => Ok("Advice".into()),
|
||||
_ => Err(syn::Error::new(
|
||||
span,
|
||||
"Invalid severity level. Only Error, Warning, and Advice are supported.",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
impl Severity {
|
||||
pub(crate) fn gen_enum(variants: &[DiagnosticDef]) -> Option<TokenStream> {
|
||||
gen_all_variants_with(
|
||||
variants,
|
||||
WhichFn::Severity,
|
||||
|ident, fields, DiagnosticConcreteArgs { severity, .. }| {
|
||||
let severity = &severity.as_ref()?.0;
|
||||
let fields = match fields {
|
||||
syn::Fields::Named(_) => quote! { { .. } },
|
||||
syn::Fields::Unnamed(_) => quote! { (..) },
|
||||
syn::Fields::Unit => quote! {},
|
||||
};
|
||||
Some(
|
||||
quote! { Self::#ident #fields => std::option::Option::Some(miette::Severity::#severity), },
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn gen_struct(&self) -> Option<TokenStream> {
|
||||
let sev = &self.0;
|
||||
Some(quote! {
|
||||
fn severity(&self) -> std::option::Option<miette::Severity> {
|
||||
Some(miette::Severity::#sev)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
81
vendor/miette-derive/src/source_code.rs
vendored
Normal file
81
vendor/miette-derive/src/source_code.rs
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
use crate::{
|
||||
diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
|
||||
forward::WhichFn,
|
||||
utils::{display_pat_members, gen_all_variants_with},
|
||||
};
|
||||
|
||||
pub struct SourceCode {
|
||||
source_code: syn::Member,
|
||||
}
|
||||
|
||||
impl SourceCode {
|
||||
pub fn from_fields(fields: &syn::Fields) -> syn::Result<Option<Self>> {
|
||||
match fields {
|
||||
syn::Fields::Named(named) => Self::from_fields_vec(named.named.iter().collect()),
|
||||
syn::Fields::Unnamed(unnamed) => {
|
||||
Self::from_fields_vec(unnamed.unnamed.iter().collect())
|
||||
}
|
||||
syn::Fields::Unit => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_fields_vec(fields: Vec<&syn::Field>) -> syn::Result<Option<Self>> {
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
for attr in &field.attrs {
|
||||
if attr.path().is_ident("source_code") {
|
||||
let source_code = if let Some(ident) = field.ident.clone() {
|
||||
syn::Member::Named(ident)
|
||||
} else {
|
||||
syn::Member::Unnamed(syn::Index {
|
||||
index: i as u32,
|
||||
span: field.span(),
|
||||
})
|
||||
};
|
||||
return Ok(Some(SourceCode { source_code }));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub(crate) fn gen_struct(&self, fields: &syn::Fields) -> Option<TokenStream> {
|
||||
let (display_pat, _display_members) = display_pat_members(fields);
|
||||
let src = &self.source_code;
|
||||
Some(quote! {
|
||||
#[allow(unused_variables)]
|
||||
fn source_code(&self) -> std::option::Option<&dyn miette::SourceCode> {
|
||||
let Self #display_pat = self;
|
||||
Some(&self.#src)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn gen_enum(variants: &[DiagnosticDef]) -> Option<TokenStream> {
|
||||
gen_all_variants_with(
|
||||
variants,
|
||||
WhichFn::SourceCode,
|
||||
|ident, fields, DiagnosticConcreteArgs { source_code, .. }| {
|
||||
let (display_pat, _display_members) = display_pat_members(fields);
|
||||
source_code.as_ref().and_then(|source_code| {
|
||||
let field = match &source_code.source_code {
|
||||
syn::Member::Named(ident) => ident.clone(),
|
||||
syn::Member::Unnamed(syn::Index { index, .. }) => {
|
||||
format_ident!("_{}", index)
|
||||
}
|
||||
};
|
||||
let variant_name = ident.clone();
|
||||
match &fields {
|
||||
syn::Fields::Unit => None,
|
||||
_ => Some(quote! {
|
||||
Self::#variant_name #display_pat => std::option::Option::Some(#field),
|
||||
}),
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
139
vendor/miette-derive/src/url.rs
vendored
Normal file
139
vendor/miette-derive/src/url.rs
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
parenthesized,
|
||||
parse::{Parse, ParseStream},
|
||||
Fields, Token,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
|
||||
utils::{display_pat_members, gen_all_variants_with, gen_unused_pat},
|
||||
};
|
||||
use crate::{
|
||||
fmt::{self, Display},
|
||||
forward::WhichFn,
|
||||
};
|
||||
|
||||
pub enum Url {
|
||||
Display(Display),
|
||||
DocsRs,
|
||||
}
|
||||
|
||||
impl Parse for Url {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let ident = input.parse::<syn::Ident>()?;
|
||||
if ident == "url" {
|
||||
let la = input.lookahead1();
|
||||
if la.peek(syn::token::Paren) {
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
if content.peek(syn::LitStr) {
|
||||
let fmt = content.parse()?;
|
||||
let args = if content.is_empty() {
|
||||
TokenStream::new()
|
||||
} else {
|
||||
fmt::parse_token_expr(&content, false)?
|
||||
};
|
||||
let display = Display {
|
||||
fmt,
|
||||
args,
|
||||
has_bonus_display: false,
|
||||
};
|
||||
Ok(Url::Display(display))
|
||||
} else {
|
||||
let option = content.parse::<syn::Ident>()?;
|
||||
if option == "docsrs" {
|
||||
Ok(Url::DocsRs)
|
||||
} else {
|
||||
Err(syn::Error::new(option.span(), "Invalid argument to url() sub-attribute. It must be either a string or a plain `docsrs` identifier"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
input.parse::<Token![=]>()?;
|
||||
Ok(Url::Display(Display {
|
||||
fmt: input.parse()?,
|
||||
args: TokenStream::new(),
|
||||
has_bonus_display: false,
|
||||
}))
|
||||
}
|
||||
} else {
|
||||
Err(syn::Error::new(ident.span(), "not a url"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Url {
|
||||
pub(crate) fn gen_enum(
|
||||
enum_name: &syn::Ident,
|
||||
variants: &[DiagnosticDef],
|
||||
) -> Option<TokenStream> {
|
||||
gen_all_variants_with(
|
||||
variants,
|
||||
WhichFn::Url,
|
||||
|ident, fields, DiagnosticConcreteArgs { url, .. }| {
|
||||
let (pat, fmt, args) = match url.as_ref()? {
|
||||
// fall through to `_ => None` below
|
||||
Url::Display(display) => {
|
||||
let (display_pat, display_members) = display_pat_members(fields);
|
||||
let (fmt, args) = display.expand_shorthand_cloned(&display_members);
|
||||
(display_pat, fmt.value(), args)
|
||||
}
|
||||
Url::DocsRs => {
|
||||
let pat = gen_unused_pat(fields);
|
||||
let fmt =
|
||||
"https://docs.rs/{crate_name}/{crate_version}/{mod_name}/{item_path}"
|
||||
.into();
|
||||
let item_path = format!("enum.{}.html#variant.{}", enum_name, ident);
|
||||
let args = quote! {
|
||||
,
|
||||
crate_name=env!("CARGO_PKG_NAME"),
|
||||
crate_version=env!("CARGO_PKG_VERSION"),
|
||||
mod_name=env!("CARGO_PKG_NAME").replace('-', "_"),
|
||||
item_path=#item_path
|
||||
};
|
||||
(pat, fmt, args)
|
||||
}
|
||||
};
|
||||
Some(quote! {
|
||||
Self::#ident #pat => std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args))),
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn gen_struct(
|
||||
&self,
|
||||
struct_name: &syn::Ident,
|
||||
fields: &Fields,
|
||||
) -> Option<TokenStream> {
|
||||
let (pat, fmt, args) = match self {
|
||||
Url::Display(display) => {
|
||||
let (display_pat, display_members) = display_pat_members(fields);
|
||||
let (fmt, args) = display.expand_shorthand_cloned(&display_members);
|
||||
(display_pat, fmt.value(), args)
|
||||
}
|
||||
Url::DocsRs => {
|
||||
let pat = gen_unused_pat(fields);
|
||||
let fmt =
|
||||
"https://docs.rs/{crate_name}/{crate_version}/{mod_name}/{item_path}".into();
|
||||
let item_path = format!("struct.{}.html", struct_name);
|
||||
let args = quote! {
|
||||
,
|
||||
crate_name=env!("CARGO_PKG_NAME"),
|
||||
crate_version=env!("CARGO_PKG_VERSION"),
|
||||
mod_name=env!("CARGO_PKG_NAME").replace('-', "_"),
|
||||
item_path=#item_path
|
||||
};
|
||||
(pat, fmt, args)
|
||||
}
|
||||
};
|
||||
Some(quote! {
|
||||
fn url(&self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>> {
|
||||
#[allow(unused_variables, deprecated)]
|
||||
let Self #pat = self;
|
||||
std::option::Option::Some(std::boxed::Box::new(format!(#fmt #args)))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
140
vendor/miette-derive/src/utils.rs
vendored
Normal file
140
vendor/miette-derive/src/utils.rs
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
spanned::Spanned,
|
||||
};
|
||||
|
||||
pub(crate) enum MemberOrString {
|
||||
Member(syn::Member),
|
||||
String(syn::LitStr),
|
||||
}
|
||||
|
||||
impl ToTokens for MemberOrString {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
use MemberOrString::*;
|
||||
match self {
|
||||
Member(member) => member.to_tokens(tokens),
|
||||
String(string) => string.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for MemberOrString {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let lookahead = input.lookahead1();
|
||||
if lookahead.peek(syn::Ident) || lookahead.peek(syn::LitInt) {
|
||||
Ok(MemberOrString::Member(input.parse()?))
|
||||
} else if lookahead.peek(syn::LitStr) {
|
||||
Ok(MemberOrString::String(input.parse()?))
|
||||
} else {
|
||||
Err(syn::Error::new(
|
||||
input.span(),
|
||||
"Expected a string or a field reference.",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use crate::{
|
||||
diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
|
||||
forward::WhichFn,
|
||||
};
|
||||
|
||||
pub(crate) fn gen_all_variants_with(
|
||||
variants: &[DiagnosticDef],
|
||||
which_fn: WhichFn,
|
||||
mut f: impl FnMut(&syn::Ident, &syn::Fields, &DiagnosticConcreteArgs) -> Option<TokenStream>,
|
||||
) -> Option<TokenStream> {
|
||||
let pairs = variants
|
||||
.iter()
|
||||
.filter_map(|def| {
|
||||
def.args
|
||||
.forward_or_override_enum(&def.ident, which_fn, |concrete| {
|
||||
f(&def.ident, &def.fields, concrete)
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if pairs.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let signature = which_fn.signature();
|
||||
let catchall = which_fn.catchall_arm();
|
||||
Some(quote! {
|
||||
#signature {
|
||||
#[allow(unused_variables, deprecated)]
|
||||
match self {
|
||||
#(#pairs)*
|
||||
#catchall
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
use crate::fmt::Display;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub(crate) fn gen_unused_pat(fields: &syn::Fields) -> TokenStream {
|
||||
match fields {
|
||||
syn::Fields::Named(_) => quote! { { .. } },
|
||||
syn::Fields::Unnamed(_) => quote! { ( .. ) },
|
||||
syn::Fields::Unit => quote! {},
|
||||
}
|
||||
}
|
||||
|
||||
/// Goes in the slot `let Self #pat = self;` or `match self { Self #pat => ...
|
||||
/// }`.
|
||||
fn gen_fields_pat(fields: &syn::Fields) -> TokenStream {
|
||||
let member_idents = fields.iter().enumerate().map(|(i, field)| {
|
||||
field
|
||||
.ident
|
||||
.as_ref()
|
||||
.cloned()
|
||||
.unwrap_or_else(|| format_ident!("_{}", i))
|
||||
});
|
||||
match fields {
|
||||
syn::Fields::Named(_) => quote! {
|
||||
{ #(#member_idents),* }
|
||||
},
|
||||
syn::Fields::Unnamed(_) => quote! {
|
||||
( #(#member_idents),* )
|
||||
},
|
||||
syn::Fields::Unit => quote! {},
|
||||
}
|
||||
}
|
||||
|
||||
/// The returned tokens go in the slot `let Self #pat = self;` or `match self {
|
||||
/// Self #pat => ... }`. The members can be passed to
|
||||
/// `Display::expand_shorthand[_cloned]`.
|
||||
pub(crate) fn display_pat_members(fields: &syn::Fields) -> (TokenStream, HashSet<syn::Member>) {
|
||||
let pat = gen_fields_pat(fields);
|
||||
let members: HashSet<syn::Member> = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, field)| {
|
||||
if let Some(ident) = field.ident.as_ref().cloned() {
|
||||
syn::Member::Named(ident)
|
||||
} else {
|
||||
syn::Member::Unnamed(syn::Index {
|
||||
index: i as u32,
|
||||
span: field.span(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
(pat, members)
|
||||
}
|
||||
|
||||
impl Display {
|
||||
/// Returns `(fmt, args)` which must be passed to some kind of format macro
|
||||
/// without tokens in between, i.e. `format!(#fmt #args)`.
|
||||
pub(crate) fn expand_shorthand_cloned(
|
||||
&self,
|
||||
members: &HashSet<syn::Member>,
|
||||
) -> (syn::LitStr, TokenStream) {
|
||||
let mut display = self.clone();
|
||||
display.expand_shorthand(members);
|
||||
let Display { fmt, args, .. } = display;
|
||||
(fmt, args)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user