diff --git a/crates/analysis/src/jobs/scan_symbols.rs b/crates/analysis/src/jobs/scan_symbols.rs index 0e80bdd7..bfcaf843 100644 --- a/crates/analysis/src/jobs/scan_symbols.rs +++ b/crates/analysis/src/jobs/scan_symbols.rs @@ -507,6 +507,10 @@ impl SyntaxNodeVisitor for SymbolScannerVisitor<'_> { } } + fn visit_global_var_decl(&mut self, n: &MemberVarDeclarationNode) { + //TODO handle annotated symbols + } + fn visit_member_func_decl(&mut self, n: &FunctionDeclarationNode, _: DeclarationTraversalContext) -> FunctionDeclarationTraversalPolicy { let mut traverse = false; diff --git a/crates/analysis/src/jobs/syntax_analysis/syntax_error_visitor.rs b/crates/analysis/src/jobs/syntax_analysis/syntax_error_visitor.rs index 0eb56eff..a661c31e 100644 --- a/crates/analysis/src/jobs/syntax_analysis/syntax_error_visitor.rs +++ b/crates/analysis/src/jobs/syntax_analysis/syntax_error_visitor.rs @@ -79,6 +79,16 @@ impl SyntaxErrorVisitor<'_> { } } + #[inline] + fn check_annotation(&mut self, n: &AnnotationNode) -> bool { + if n.has_errors() { + self.check_errors(n); + false + } else { + true + } + } + fn check_errors(&mut self, n: &SyntaxNode<'_, T>) { let errors = n.errors(); if errors.is_empty() { @@ -229,8 +239,25 @@ impl SyntaxNodeVisitor for SyntaxErrorVisitor<'_> { } } + fn visit_global_var_decl(&mut self, n: &MemberVarDeclarationNode) { + if n.has_errors() { + if let Some(annot) = n.annotation() { + self.check_annotation(&annot); + } + + n.names().for_each(|name| { self.check_identifier(&name); } ); + self.check_type_annot(&n.var_type()); + + self.check_errors(n); + } + } + fn visit_member_var_decl(&mut self, n: &MemberVarDeclarationNode, _: DeclarationTraversalContext) { if n.has_errors() { + if let Some(annot) = n.annotation() { + self.check_annotation(&annot); + } + n.names().for_each(|name| { self.check_identifier(&name); } ); self.check_type_annot(&n.var_type()); @@ -285,6 +312,10 @@ impl SyntaxNodeVisitor for SyntaxErrorVisitor<'_> { let mut traverse_params = false; let mut traverse_definition = false; if n.has_errors() { + if let Some(annot) = n.annotation() { + self.check_annotation(&annot); + } + self.check_identifier(&n.name()); n.return_type().map(|n| self.check_type_annot(&n)); @@ -315,6 +346,10 @@ impl SyntaxNodeVisitor for SyntaxErrorVisitor<'_> { let mut traverse_params = false; let mut traverse_definition = false; if n.has_errors() { + if let Some(annot) = n.annotation() { + self.check_annotation(&annot); + } + self.check_identifier(&n.name()); if let Some(ret) = n.return_type() { diff --git a/crates/analysis/src/symbol_analysis/unqualified_name_lookup.rs b/crates/analysis/src/symbol_analysis/unqualified_name_lookup.rs index 1efc9ca3..a3e30285 100644 --- a/crates/analysis/src/symbol_analysis/unqualified_name_lookup.rs +++ b/crates/analysis/src/symbol_analysis/unqualified_name_lookup.rs @@ -351,6 +351,8 @@ impl SyntaxNodeVisitor for UnqualifiedNameLookupBuilder<'_> { unl.push_scope(); + //TODO handle annotated functions + if let Some((func_symtab, func_symvar)) = self.symtab_marcher.get_symbol_with_containing_table(&sympath_ctx.current_sympath) { if let Some(func) = func_symvar.try_as_global_func_ref() { for ch in func_symtab.get_symbol_children_filtered(func) { diff --git a/crates/analysis/src/utils/visitors/position_filter.rs b/crates/analysis/src/utils/visitors/position_filter.rs index 901f0f00..d13f8028 100644 --- a/crates/analysis/src/utils/visitors/position_filter.rs +++ b/crates/analysis/src/utils/visitors/position_filter.rs @@ -170,6 +170,13 @@ impl SyntaxNodeVisitor for PositionFilter { self.currently_in_callable_range = false; } + fn visit_global_var_decl(&mut self, n: &MemberVarDeclarationNode) { + self.currently_in_range = n.spans_position(self.pos); + if self.currently_in_range { + self.payload.borrow_mut().done = true; + } + } + diff --git a/crates/analysis/src/utils/visitors/sympath_builder.rs b/crates/analysis/src/utils/visitors/sympath_builder.rs index a92ce9dd..4e0e6239 100644 --- a/crates/analysis/src/utils/visitors/sympath_builder.rs +++ b/crates/analysis/src/utils/visitors/sympath_builder.rs @@ -99,6 +99,8 @@ impl SyntaxNodeVisitor for SymbolPathBuilder<'_> { let name = n.name().value(self.doc); self.payload.borrow_mut().current_sympath = GlobalCallableSymbolPath::new(&name).into(); TraversalPolicy::default_to(true) + + //TODO handle annotated functions } fn exit_global_func_decl(&mut self, _: &FunctionDeclarationNode) { diff --git a/crates/core/src/ast/annotation.rs b/crates/core/src/ast/annotation.rs new file mode 100644 index 00000000..ea981c96 --- /dev/null +++ b/crates/core/src/ast/annotation.rs @@ -0,0 +1,60 @@ +use strum_macros::{EnumString, Display, AsRefStr}; +use crate::{AnyNode, DebugRange, NamedSyntaxNode, SyntaxNode}; +use crate::tokens::{AnnotationIdentifierNode, IdentifierNode}; + + +mod tags { + pub struct Annotation; +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumString, Display, AsRefStr)] +pub enum AnnotationKind { + #[strum(serialize="@addMethod")] + AddMethod, + #[strum(serialize="@addField")] + AddField, + #[strum(serialize="@replaceMethod")] + ReplaceMethod, + #[strum(serialize="@wrapMethod")] + WrapMethod +} + +pub const WRAPPED_METHOD_NAME: &'static str = "wrappedMethod"; + + +pub type AnnotationNode<'script> = SyntaxNode<'script, tags::Annotation>; + +impl NamedSyntaxNode for AnnotationNode<'_> { + const NODE_KIND: &'static str = "annotation"; +} + +impl<'script> AnnotationNode<'script> { + pub fn name(&self) -> AnnotationIdentifierNode<'script> { + self.field_child("name").unwrap().into() + } + + pub fn arg(&self) -> Option> { + self.field_child("arg").map(|n| n.into()) + } +} + +impl std::fmt::Debug for AnnotationNode<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct(&format!("Annotation {}", self.range().debug())) + .field("name", &self.name()) + .field("arg", &self.arg()) + .finish() + } +} + +impl<'script> TryFrom> for AnnotationNode<'script> { + type Error = (); + + fn try_from(value: AnyNode<'script>) -> Result { + if value.tree_node.kind() == Self::NODE_KIND { + Ok(value.into()) + } else { + Err(()) + } + } +} \ No newline at end of file diff --git a/crates/core/src/ast/functions.rs b/crates/core/src/ast/functions.rs index 6748542b..f8626164 100644 --- a/crates/core/src/ast/functions.rs +++ b/crates/core/src/ast/functions.rs @@ -88,6 +88,10 @@ impl NamedSyntaxNode for FunctionDeclarationNode<'_> { } impl<'script> FunctionDeclarationNode<'script> { + pub fn annotation(&self) -> Option> { + self.field_child("annotation").map(|n| n.into()) + } + pub fn specifiers(&self) -> impl Iterator> { self.field_children("specifiers").map(|n| n.into()) } @@ -116,6 +120,7 @@ impl<'script> FunctionDeclarationNode<'script> { impl Debug for FunctionDeclarationNode<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(&format!("FunctionDeclaration {}", self.range().debug())) + .field("annotation", &self.annotation()) .field("specifiers", &self.specifiers().collect::>()) .field("flavour", &self.flavour()) .field("name", &self.name()) diff --git a/crates/core/src/ast/mod.rs b/crates/core/src/ast/mod.rs index 76e15d3a..e87dfa6c 100644 --- a/crates/core/src/ast/mod.rs +++ b/crates/core/src/ast/mod.rs @@ -7,6 +7,7 @@ mod vars; mod structs; mod enums; mod states; +mod annotation; mod nop; mod root; mod traversal; @@ -20,6 +21,7 @@ pub use vars::*; pub use structs::*; pub use enums::*; pub use states::*; +pub use annotation::*; pub use nop::*; pub use root::*; pub use traversal::*; \ No newline at end of file diff --git a/crates/core/src/ast/traversal/visitor.rs b/crates/core/src/ast/traversal/visitor.rs index 094c0954..d0c6fa91 100644 --- a/crates/core/src/ast/traversal/visitor.rs +++ b/crates/core/src/ast/traversal/visitor.rs @@ -117,6 +117,11 @@ pub trait SyntaxNodeVisitor { /// Called when visiting enum variant's declaration. fn visit_enum_variant_decl(&mut self, n: &EnumVariantDeclarationNode) {} + /// Called when visiting a variable declaration in the global scope. + /// THIS IS NOT LEGAL SYNTAX BY ITSELF. + /// It it allowed here purely to be able to parse @addField variables. + fn visit_global_var_decl(&mut self, n: &MemberVarDeclarationNode) {} + /// Called when visiting member variable (i.e. field) declaration. fn visit_member_var_decl(&mut self, n: &MemberVarDeclarationNode, ctx: DeclarationTraversalContext) {} diff --git a/crates/core/src/ast/traversal/visitor_chain.rs b/crates/core/src/ast/traversal/visitor_chain.rs index 6bbde523..e8f2cafa 100644 --- a/crates/core/src/ast/traversal/visitor_chain.rs +++ b/crates/core/src/ast/traversal/visitor_chain.rs @@ -140,6 +140,10 @@ impl<'a> SyntaxNodeVisitor for SyntaxNodeVisitorChain<'a> { self.chain_exit(move |link| link.exit_global_func_decl(n)) } + fn visit_global_var_decl(&mut self, n: &MemberVarDeclarationNode) { + self.chain_visit(move |link| link.visit_global_var_decl(n)) + } + fn visit_member_func_decl(&mut self, n: &FunctionDeclarationNode, ctx: DeclarationTraversalContext) -> FunctionDeclarationTraversalPolicy { diff --git a/crates/core/src/ast/vars.rs b/crates/core/src/ast/vars.rs index 576ffad5..79fb94cb 100644 --- a/crates/core/src/ast/vars.rs +++ b/crates/core/src/ast/vars.rs @@ -112,6 +112,10 @@ impl NamedSyntaxNode for MemberVarDeclarationNode<'_> { } impl<'script> MemberVarDeclarationNode<'script> { + pub fn annotation(&self) -> Option> { + self.field_child("annotation").map(|n| n.into()) + } + pub fn specifiers(&self) -> impl Iterator> { self.field_children("specifiers").map(|n| n.into()) } @@ -128,6 +132,7 @@ impl<'script> MemberVarDeclarationNode<'script> { impl Debug for MemberVarDeclarationNode<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(&format!("MemberVarDeclaration {}", self.range().debug())) + .field("annotation", &self.annotation()) .field("specifiers", &self.specifiers().collect::>()) .field("names", &self.names().collect::>()) .field("var_type", &self.var_type()) diff --git a/crates/core/src/tokens/identifier.rs b/crates/core/src/tokens/identifier.rs index 93bd5fe5..06012bf9 100644 --- a/crates/core/src/tokens/identifier.rs +++ b/crates/core/src/tokens/identifier.rs @@ -53,6 +53,57 @@ impl SyntaxNodeTraversal for IdentifierNode<'_> { impl<'script> TryFrom> for IdentifierNode<'script> { type Error = (); + fn try_from(value: AnyNode<'script>) -> Result { + if value.tree_node.is_named() && value.tree_node.kind() == Self::NODE_KIND { + Ok(value.into()) + } else { + Err(()) + } + } +} + + + + +#[derive(Shrinkwrap, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct AnnotationIdentifier<'d>(Cow<'d, str>); + +impl std::fmt::Display for AnnotationIdentifier<'_> { + #[inline] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl<'d, S: AsRef> PartialEq for AnnotationIdentifier<'d> { + #[inline] + fn eq(&self, other: &S) -> bool { + self.0 == other.as_ref() + } +} + + +pub type AnnotationIdentifierNode<'script> = SyntaxNode<'script, AnnotationIdentifier<'script>>; + +impl NamedSyntaxNode for AnnotationIdentifierNode<'_> { + const NODE_KIND: &'static str = "annotation_ident"; +} + +impl AnnotationIdentifierNode<'_> { + pub fn value<'d>(&self, doc: &'d ScriptDocument) -> AnnotationIdentifier<'d> { + AnnotationIdentifier(self.text(doc)) + } +} + +impl Debug for AnnotationIdentifierNode<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "AnnotationIdentifier {}", self.range().debug()) + } +} + +impl<'script> TryFrom> for AnnotationIdentifierNode<'script> { + type Error = (); + fn try_from(value: AnyNode<'script>) -> Result { if value.tree_node.is_named() && value.tree_node.kind() == Self::NODE_KIND { Ok(value.into()) diff --git a/crates/lsp/src/providers/common.rs b/crates/lsp/src/providers/common.rs index b6afaca5..4e5b240a 100644 --- a/crates/lsp/src/providers/common.rs +++ b/crates/lsp/src/providers/common.rs @@ -315,6 +315,10 @@ impl SyntaxNodeVisitor for TextDocumentPositionResolver<'_> { } } + fn visit_global_var_decl(&mut self, n: &MemberVarDeclarationNode) { + //TODO handle annotated var + } + fn visit_member_var_decl(&mut self, n: &MemberVarDeclarationNode, _: DeclarationTraversalContext) { let var_type = n.var_type(); @@ -375,6 +379,8 @@ impl SyntaxNodeVisitor for TextDocumentPositionResolver<'_> { fn visit_global_func_decl(&mut self, n: &FunctionDeclarationNode) -> FunctionDeclarationTraversalPolicy { + //TODO handle annotated functions + if self.pos_filter_payload.borrow().done { let name = n.name(); diff --git a/crates/lsp/src/providers/selection_range.rs b/crates/lsp/src/providers/selection_range.rs index 36e8d973..af0cd299 100644 --- a/crates/lsp/src/providers/selection_range.rs +++ b/crates/lsp/src/providers/selection_range.rs @@ -94,6 +94,19 @@ impl SelectionRangeResolver { } } } + + fn visit_annotation(&mut self, n: &AnnotationNode) { + self.range_stack.push(n.range()); + + if n.name().spans_position(self.pos) { + self.range_stack.push(n.name().range()); + } + else if let Some(arg) = n.arg() { + if arg.spans_position(self.pos) { + self.range_stack.push(arg.range()); + } + } + } } impl SyntaxNodeVisitor for SelectionRangeResolver { @@ -207,7 +220,10 @@ impl SyntaxNodeVisitor for SelectionRangeResolver { self.range_stack.push(n.range()); if self.payload.borrow().done { - if n.name().spans_position(self.pos) { + if let Some(annot) = n.annotation().filter(|annot| annot.spans_position(self.pos)) { + self.visit_annotation(&annot); + } + else if n.name().spans_position(self.pos) { self.range_stack.push(n.name().range()); } else if let Some(rt) = n.return_type().filter(|rt| rt.spans_position(self.pos)) { @@ -230,6 +246,23 @@ impl SyntaxNodeVisitor for SelectionRangeResolver { TraversalPolicy::default_to(true) } + fn visit_global_var_decl(&mut self, n: &MemberVarDeclarationNode) { + self.range_stack.push(n.range()); + + if let Some(annot) = n.annotation().filter(|annot| annot.spans_position(self.pos)) { + self.visit_annotation(&annot); + } + else if n.var_type().spans_position(self.pos) { + self.visit_type_annotation(&n.var_type()); + } + else if let Some(name) = n.names().find(|name| name.spans_position(self.pos)) { + self.range_stack.push(name.range()); + } + else if let Some(spec) = n.specifiers().find(|spec| spec.spans_position(self.pos)) { + self.range_stack.push(spec.range()); + } + } + @@ -237,7 +270,10 @@ impl SyntaxNodeVisitor for SelectionRangeResolver { self.range_stack.push(n.range()); if self.payload.borrow().done { - if n.name().spans_position(self.pos) { + if let Some(annot) = n.annotation().filter(|annot| annot.spans_position(self.pos)) { + self.visit_annotation(&annot); + } + else if n.name().spans_position(self.pos) { self.range_stack.push(n.name().range()); } else if let Some(rt) = n.return_type().filter(|rt| rt.spans_position(self.pos)) { @@ -298,7 +334,10 @@ impl SyntaxNodeVisitor for SelectionRangeResolver { fn visit_member_var_decl(&mut self, n: &MemberVarDeclarationNode, _: DeclarationTraversalContext) { self.range_stack.push(n.range()); - if n.var_type().spans_position(self.pos) { + if let Some(annot) = n.annotation().filter(|annot| annot.spans_position(self.pos)) { + self.visit_annotation(&annot); + } + else if n.var_type().spans_position(self.pos) { self.visit_type_annotation(&n.var_type()); } else if let Some(name) = n.names().find(|name| name.spans_position(self.pos)) {