Skip to content

Commit

Permalink
More accurately provide spans to errors in the GodotClass macro
Browse files Browse the repository at this point in the history
  • Loading branch information
lilizoey committed Oct 15, 2024
1 parent a0d5799 commit 623aa41
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 63 deletions.
28 changes: 26 additions & 2 deletions godot-macros/src/class/data_models/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@
*/

use crate::class::{FieldExport, FieldVar};
use proc_macro2::{Ident, TokenStream};
use proc_macro2::{Ident, Span, TokenStream};
use quote::ToTokens;
use venial::Error;

pub struct Field {
pub name: Ident,
pub ty: venial::TypeExpr,
pub default_val: Option<TokenStream>,
pub default_val: Option<FieldDefault>,
pub var: Option<FieldVar>,
pub export: Option<FieldExport>,
pub is_onready: bool,
#[cfg(feature = "docs")]
pub attributes: Vec<venial::Attribute>,
pub span: Span,
}

impl Field {
Expand All @@ -30,6 +33,7 @@ impl Field {
is_onready: false,
#[cfg(feature = "docs")]
attributes: field.attributes.clone(),
span: field.span(),
}
}
}
Expand All @@ -41,6 +45,26 @@ pub struct Fields {
/// The field with type `Base<T>`, if available.
pub base_field: Option<Field>,

/// The base field is either absent or is correctly formatted.
///
/// When this is false, there will always be a compile error ensuring the program fails to compile.
pub well_formed_base: bool,

/// Deprecation warnings.
pub deprecations: Vec<TokenStream>,

/// Errors during macro evaluation that shouldn't abort the execution of the macro.
pub errors: Vec<Error>,
}

#[derive(Clone)]
pub struct FieldDefault {
pub default_val: TokenStream,
pub span: Span,
}

impl ToTokens for FieldDefault {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.default_val.to_tokens(tokens)
}
}
65 changes: 41 additions & 24 deletions godot-macros/src/class/data_models/field_export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,32 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use proc_macro2::{Ident, TokenStream};
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
use std::collections::{HashMap, HashSet};

use crate::util::{KvParser, ListParser};
use crate::ParseResult;

pub struct FieldExport {
pub export_type: ExportType,
pub span: Span,
}

impl FieldExport {
pub(crate) fn new_from_kv(parser: &mut KvParser) -> ParseResult<Self> {
let span = parser.span();
let export_type = ExportType::new_from_kv(parser)?;
Ok(Self { export_type, span })
}

pub fn to_export_hint(&self) -> Option<TokenStream> {
self.export_type.to_export_hint()
}
}

/// Store info from `#[export]` attribute.
pub enum FieldExport {
pub enum ExportType {
/// ### GDScript annotations
/// - `@export`
///
Expand Down Expand Up @@ -121,7 +138,7 @@ pub enum FieldExport {
ColorNoAlpha,
}

impl FieldExport {
impl ExportType {
/// Parse an `#[export(...)]` attribute.
///
/// The translation from GDScript annotations to rust attributes is given by:
Expand Down Expand Up @@ -253,10 +270,10 @@ impl FieldExport {
return Ok(Self::ColorNoAlpha);
}

Ok(FieldExport::Default)
Ok(Self::Default)
}

fn new_range_list(mut parser: ListParser) -> ParseResult<FieldExport> {
fn new_range_list(mut parser: ListParser) -> ParseResult<Self> {
const FLAG_OPTIONS: [&str; 7] = [
"or_greater",
"or_less",
Expand Down Expand Up @@ -299,7 +316,7 @@ impl FieldExport {

parser.finish()?;

Ok(FieldExport::Range {
Ok(Self::Range {
min,
max,
step,
Expand Down Expand Up @@ -374,12 +391,12 @@ macro_rules! quote_export_func {
}
}

impl FieldExport {
impl ExportType {
pub fn to_export_hint(&self) -> Option<TokenStream> {
match self {
FieldExport::Default => None,
Self::Default => None,

FieldExport::Range {
Self::Range {
min,
max,
step,
Expand Down Expand Up @@ -416,70 +433,70 @@ impl FieldExport {
})
}

FieldExport::Enum { variants } => {
Self::Enum { variants } => {
let variants = variants.iter().map(ValueWithKey::to_tuple_expression);

quote_export_func! {
export_enum(&[#(#variants),*])
}
}

FieldExport::ExpEasing {
Self::ExpEasing {
attenuation,
positive_only,
} => quote_export_func! {
export_exp_easing(#attenuation, #positive_only)
},

FieldExport::Flags { bits } => {
Self::Flags { bits } => {
let bits = bits.iter().map(ValueWithKey::to_tuple_expression);

quote_export_func! {
export_flags(&[#(#bits),*])
}
}

FieldExport::Layers {
Self::Layers {
dimension: LayerDimension::_2d,
kind: LayerKind::Physics,
} => quote_export_func! { export_flags_2d_physics() },

FieldExport::Layers {
Self::Layers {
dimension: LayerDimension::_2d,
kind: LayerKind::Render,
} => quote_export_func! { export_flags_2d_render() },

FieldExport::Layers {
Self::Layers {
dimension: LayerDimension::_2d,
kind: LayerKind::Navigation,
} => quote_export_func! { export_flags_2d_navigation() },

FieldExport::Layers {
Self::Layers {
dimension: LayerDimension::_3d,
kind: LayerKind::Physics,
} => quote_export_func! { export_flags_3d_physics() },

FieldExport::Layers {
Self::Layers {
dimension: LayerDimension::_3d,
kind: LayerKind::Render,
} => quote_export_func! { export_flags_3d_render() },

FieldExport::Layers {
Self::Layers {
dimension: LayerDimension::_3d,
kind: LayerKind::Navigation,
} => quote_export_func! { export_flags_3d_navigation() },

FieldExport::File {
Self::File {
global: false,
kind: FileKind::Dir,
} => quote_export_func! { export_dir() },

FieldExport::File {
Self::File {
global: true,
kind: FileKind::Dir,
} => quote_export_func! { export_global_dir() },

FieldExport::File {
Self::File {
global,
kind: FileKind::File { filter },
} => {
Expand All @@ -488,12 +505,12 @@ impl FieldExport {
quote_export_func! { export_file_inner(#global, #filter) }
}

FieldExport::Multiline => quote_export_func! { export_multiline() },
Self::Multiline => quote_export_func! { export_multiline() },

FieldExport::PlaceholderText { placeholder } => quote_export_func! {
Self::PlaceholderText { placeholder } => quote_export_func! {
export_placeholder(#placeholder)
},
FieldExport::ColorNoAlpha => quote_export_func! { export_color_no_alpha() },
Self::ColorNoAlpha => quote_export_func! { export_color_no_alpha() },
}
}
}
Expand Down
19 changes: 17 additions & 2 deletions godot-macros/src/class/data_models/field_var.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

use proc_macro2::{Ident, TokenStream};
use proc_macro2::{Ident, Span, TokenStream};
use quote::{format_ident, quote};

use crate::class::{
Expand All @@ -16,12 +16,13 @@ use crate::util::KvParser;
use crate::{util, ParseResult};

/// Store info from `#[var]` attribute.
#[derive(Default, Clone, Debug)]
#[derive(Clone, Debug)]
pub struct FieldVar {
pub getter: GetterSetter,
pub setter: GetterSetter,
pub hint: FieldHint,
pub usage_flags: UsageFlags,
pub span: Span,
}

impl FieldVar {
Expand All @@ -34,6 +35,7 @@ impl FieldVar {
/// - `hint_string = expr`
/// - `usage_flags =
pub(crate) fn new_from_kv(parser: &mut KvParser) -> ParseResult<Self> {
let span = parser.span();
let mut getter = GetterSetter::parse(parser, "get")?;
let mut setter = GetterSetter::parse(parser, "set")?;

Expand Down Expand Up @@ -71,10 +73,23 @@ impl FieldVar {
setter,
hint,
usage_flags,
span,
})
}
}

impl Default for FieldVar {
fn default() -> Self {
Self {
getter: Default::default(),
setter: Default::default(),
hint: Default::default(),
usage_flags: Default::default(),
span: Span::call_site(),
}
}
}

#[derive(Default, Clone, Eq, PartialEq, Debug)]
pub enum GetterSetter {
/// Getter/setter should be omitted, field is write/read only.
Expand Down
1 change: 1 addition & 0 deletions godot-macros/src/class/data_models/property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ pub fn make_property_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
setter,
hint,
mut usage_flags,
..
} = var;

let export_hint;
Expand Down
Loading

0 comments on commit 623aa41

Please sign in to comment.