Skip to content

Commit

Permalink
Add Annotation to the AST
Browse files Browse the repository at this point in the history
  • Loading branch information
SpontanCombust committed Jun 11, 2024
1 parent fa1015c commit bfa5f80
Show file tree
Hide file tree
Showing 14 changed files with 230 additions and 3 deletions.
4 changes: 4 additions & 0 deletions crates/analysis/src/jobs/scan_symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
35 changes: 35 additions & 0 deletions crates/analysis/src/jobs/syntax_analysis/syntax_error_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(&mut self, n: &SyntaxNode<'_, T>) {
let errors = n.errors();
if errors.is_empty() {
Expand Down Expand Up @@ -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());

Expand Down Expand Up @@ -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));

Expand Down Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
7 changes: 7 additions & 0 deletions crates/analysis/src/utils/visitors/position_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}




Expand Down
2 changes: 2 additions & 0 deletions crates/analysis/src/utils/visitors/sympath_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
60 changes: 60 additions & 0 deletions crates/core/src/ast/annotation.rs
Original file line number Diff line number Diff line change
@@ -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<IdentifierNode<'script>> {
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<AnyNode<'script>> for AnnotationNode<'script> {
type Error = ();

fn try_from(value: AnyNode<'script>) -> Result<Self, Self::Error> {
if value.tree_node.kind() == Self::NODE_KIND {
Ok(value.into())
} else {
Err(())
}
}
}
5 changes: 5 additions & 0 deletions crates/core/src/ast/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ impl NamedSyntaxNode for FunctionDeclarationNode<'_> {
}

impl<'script> FunctionDeclarationNode<'script> {
pub fn annotation(&self) -> Option<AnnotationNode<'script>> {
self.field_child("annotation").map(|n| n.into())
}

pub fn specifiers(&self) -> impl Iterator<Item = SpecifierNode<'script>> {
self.field_children("specifiers").map(|n| n.into())
}
Expand Down Expand Up @@ -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::<Vec<_>>())
.field("flavour", &self.flavour())
.field("name", &self.name())
Expand Down
2 changes: 2 additions & 0 deletions crates/core/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod vars;
mod structs;
mod enums;
mod states;
mod annotation;
mod nop;
mod root;
mod traversal;
Expand All @@ -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::*;
5 changes: 5 additions & 0 deletions crates/core/src/ast/traversal/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}

Expand Down
4 changes: 4 additions & 0 deletions crates/core/src/ast/traversal/visitor_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions crates/core/src/ast/vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ impl NamedSyntaxNode for MemberVarDeclarationNode<'_> {
}

impl<'script> MemberVarDeclarationNode<'script> {
pub fn annotation(&self) -> Option<AnnotationNode<'script>> {
self.field_child("annotation").map(|n| n.into())
}

pub fn specifiers(&self) -> impl Iterator<Item = SpecifierNode<'script>> {
self.field_children("specifiers").map(|n| n.into())
}
Expand All @@ -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::<Vec<_>>())
.field("names", &self.names().collect::<Vec<_>>())
.field("var_type", &self.var_type())
Expand Down
51 changes: 51 additions & 0 deletions crates/core/src/tokens/identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,57 @@ impl SyntaxNodeTraversal for IdentifierNode<'_> {
impl<'script> TryFrom<AnyNode<'script>> for IdentifierNode<'script> {
type Error = ();

fn try_from(value: AnyNode<'script>) -> Result<Self, Self::Error> {
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<str>> PartialEq<S> 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<AnyNode<'script>> for AnnotationIdentifierNode<'script> {
type Error = ();

fn try_from(value: AnyNode<'script>) -> Result<Self, Self::Error> {
if value.tree_node.is_named() && value.tree_node.kind() == Self::NODE_KIND {
Ok(value.into())
Expand Down
6 changes: 6 additions & 0 deletions crates/lsp/src/providers/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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();

Expand Down
Loading

0 comments on commit bfa5f80

Please sign in to comment.