From 6bc1a6fcc84f04792c66e5f5191c4ac0eba4c6b8 Mon Sep 17 00:00:00 2001 From: SpontanCombust <61706594+SpontanCombust@users.noreply.github.com> Date: Wed, 14 Aug 2024 15:19:27 +0200 Subject: [PATCH] bumped grammar version: updated features + added array initializer expression --- Cargo.lock | 23 ++++-- crates/core/Cargo.toml | 4 +- crates/core/src/ast/expressions.rs | 77 ++++++++++++++++++- crates/core/src/ast/traversal/contexts.rs | 1 + crates/core/src/ast/traversal/policies.rs | 34 ++++++++ crates/core/src/ast/traversal/visitor.rs | 10 +++ .../core/src/ast/traversal/visitor_chain.rs | 10 +++ crates/core/src/script.rs | 2 +- crates/core/src/syntax_node.rs | 4 +- crates/core/src/syntax_node_any.rs | 1 + 10 files changed, 152 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c643178..9d25414b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -219,12 +219,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.90" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "5fb8dd288a69fc53a1996d7ecfbf4a20d59065bff137ce7e56bbd620de191189" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -942,9 +943,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -1074,6 +1075,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "shrinkwraprs" version = "0.3.0" @@ -1385,9 +1392,9 @@ dependencies = [ [[package]] name = "tree-sitter" -version = "0.20.10" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e747b1f9b7b931ed39a548c1fae149101497de3c1fc8d9e18c62c1a66c683d3d" +checksum = "df7cc499ceadd4dcdf7ec6d4cbc34ece92c3fa07821e287aedecd4416c516dca" dependencies = [ "cc", "regex", @@ -1395,8 +1402,8 @@ dependencies = [ [[package]] name = "tree-sitter-witcherscript" -version = "0.10.1" -source = "git+https://github.com/SpontanCombust/tree-sitter-witcherscript.git?tag=v0.11.0#31dae31b5c0165547ba1ec63c1467169ab0020fb" +version = "0.12.0" +source = "git+https://github.com/SpontanCombust/tree-sitter-witcherscript.git?tag=v0.12.0#b9b9e45f2e3d2c1798c4b06567d66066cf0ee8d5" dependencies = [ "cc", "tree-sitter", diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index f38ad21a..a1d41e7a 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -13,9 +13,9 @@ thiserror.workspace = true shrinkwraprs.workspace = true ropey.workspace = true lsp-types.workspace = true -tree-sitter = "0.20" +tree-sitter = ">=0.22.6" encoding_rs_io = "0.1" [dependencies.tree-sitter-witcherscript] git = "https://github.com/SpontanCombust/tree-sitter-witcherscript.git" -tag = "v0.11.0" \ No newline at end of file +tag = "v0.12.0" \ No newline at end of file diff --git a/crates/core/src/ast/expressions.rs b/crates/core/src/ast/expressions.rs index 769c0e36..741ae4a4 100644 --- a/crates/core/src/ast/expressions.rs +++ b/crates/core/src/ast/expressions.rs @@ -20,6 +20,7 @@ mod tags { pub struct BinaryOperationExpression; pub struct AssignmentOperationExpression; pub struct TernaryConditionalExpression; + pub struct ArrayInitializerExpression; pub struct ExpressionStatement; } @@ -1007,6 +1008,69 @@ impl SyntaxNodeTraversal for TernaryConditionalExpressionNode<'_> { +pub type ArrayInitializerExpressionNode<'script> = SyntaxNode<'script, tags::ArrayInitializerExpression>; + +impl NamedSyntaxNode for ArrayInitializerExpressionNode<'_> { + const NODE_KIND: &'static str = "array_init_expr"; +} + +impl<'script> ArrayInitializerExpressionNode<'script> { + pub fn iter(&self) -> impl Iterator> { + self.named_children().map(|ch| ch.unsafe_into()) + } +} + +impl Debug for ArrayInitializerExpressionNode<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_maybe_alternate_named( + &format!("ArrayInitializerExpression {}", self.range().debug()), + &self.iter().collect::>() + ) + } +} + +impl<'script> TryFrom> for ArrayInitializerExpressionNode<'script> { + type Error = (); + + fn try_from(value: AnyNode<'script>) -> Result { + if value.tree_node.kind() == Self::NODE_KIND { + Ok(value.unsafe_into()) + } else { + Err(()) + } + } +} + +impl SyntaxNodeTraversal for ArrayInitializerExpressionNode<'_> { + fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { + let tp = visitor.visit_array_initializer_expr(self, ctx); + + if tp.any() { + ctx.push(TraversalContext::ArrayInitializerExpression); + + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((item, _)) if tp.traverse_items => { + let item: ExpressionNode = item.unsafe_into(); + + item.accept(visitor, ctx); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + + ctx.pop(); + } + + visitor.exit_array_initializer_expr(self, ctx); + } +} + + + // Represents the unnamed $._expr node #[derive(Clone)] pub enum Expression<'script> { @@ -1026,6 +1090,7 @@ pub enum Expression<'script> { BinaryOperation(BinaryOperationExpressionNode<'script>), AssignmentOperation(AssignmentOperationExpressionNode<'script>), TernaryConditional(TernaryConditionalExpressionNode<'script>), + ArrayInitializer(ArrayInitializerExpressionNode<'script>) } impl Debug for Expression<'_> { @@ -1047,6 +1112,7 @@ impl Debug for Expression<'_> { Self::BinaryOperation(n) => f.debug_maybe_alternate(n), Self::AssignmentOperation(n) => f.debug_maybe_alternate(n), Self::TernaryConditional(n) => f.debug_maybe_alternate(n), + Self::ArrayInitializer(n) => f.debug_maybe_alternate(n), } } } @@ -1078,6 +1144,7 @@ impl<'script> ExpressionNode<'script> { LiteralStringNode::NODE_KIND | LiteralNameNode::NODE_KIND | LiteralNullNode::NODE_KIND => Expression::Literal(self.unsafe_into()), + ArrayInitializerExpressionNode::NODE_KIND => Expression::ArrayInitializer(self.unsafe_into()), _ => panic!("Unknown expression type: {} {}", self.tree_node.kind(), self.range().debug()) } } @@ -1119,7 +1186,8 @@ impl<'script> TryFrom> for ExpressionNode<'script> { LiteralBoolNode::NODE_KIND | LiteralStringNode::NODE_KIND | LiteralNameNode::NODE_KIND | - LiteralNullNode::NODE_KIND => Ok(value.unsafe_into()), + LiteralNullNode::NODE_KIND | + ArrayInitializerExpressionNode::NODE_KIND => Ok(value.unsafe_into()), _ => Err(()) } } @@ -1221,6 +1289,12 @@ impl<'script> From> for ExpressionNode } } +impl<'script> From> for ExpressionNode<'script> { + fn from(value: ArrayInitializerExpressionNode<'script>) -> Self { + value.unsafe_into() + } +} + impl SyntaxNodeTraversal for ExpressionNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { match self.clone().value() { @@ -1240,6 +1314,7 @@ impl SyntaxNodeTraversal for ExpressionNode<'_> { Expression::BinaryOperation(n) => n.accept(visitor, ctx), Expression::AssignmentOperation(n) => n.accept(visitor, ctx), Expression::TernaryConditional(n) => n.accept(visitor, ctx), + Expression::ArrayInitializer(n) => n.accept(visitor, ctx), } } } diff --git a/crates/core/src/ast/traversal/contexts.rs b/crates/core/src/ast/traversal/contexts.rs index 2af019cd..dc2ebf78 100644 --- a/crates/core/src/ast/traversal/contexts.rs +++ b/crates/core/src/ast/traversal/contexts.rs @@ -59,6 +59,7 @@ pub enum TraversalContext { TernaryConditionalExpressionCond, TernaryConditionalExpressionConseq, TernaryConditionalExpressionAlt, + ArrayInitializerExpression, Error } diff --git a/crates/core/src/ast/traversal/policies.rs b/crates/core/src/ast/traversal/policies.rs index cebff82f..a8d7872f 100644 --- a/crates/core/src/ast/traversal/policies.rs +++ b/crates/core/src/ast/traversal/policies.rs @@ -401,6 +401,40 @@ impl BitAnd for TernaryConditionalExpressionTraversalPolicy { } +#[derive(Debug, Clone)] +pub struct ArrayInitializerExpressionTraversalPolicy { + pub traverse_items: bool, + pub traverse_errors: bool +} + +impl TraversalPolicy for ArrayInitializerExpressionTraversalPolicy { + #[inline(always)] + fn default_to(value: bool) -> Self { + Self { + traverse_items: value, + traverse_errors: value + } + } + + #[inline] + fn any(&self) -> bool { + self.traverse_items || + self.traverse_errors + } +} + +impl BitAnd for ArrayInitializerExpressionTraversalPolicy { + type Output = Self; + + fn bitand(self, rhs: Self) -> Self::Output { + Self { + traverse_items: self.traverse_items && rhs.traverse_items, + traverse_errors: self.traverse_errors && rhs.traverse_errors + } + } +} + + #[derive(Debug, Clone)] diff --git a/crates/core/src/ast/traversal/visitor.rs b/crates/core/src/ast/traversal/visitor.rs index 429d27e2..1c292c53 100644 --- a/crates/core/src/ast/traversal/visitor.rs +++ b/crates/core/src/ast/traversal/visitor.rs @@ -88,6 +88,16 @@ pub trait SyntaxNodeVisitor { /// Called after visiting a ternary conditional expression and possibly also children nodes specified in traversal policy. fn exit_ternary_cond_expr(&mut self, n: &TernaryConditionalExpressionNode, ctx: &TraversalContextStack) {} + /// Called when visiting an array initializer expression. + /// Array initializer can be used in the `default` statement context to initialize a member array. + /// The syntax for it is like in C++: + /// ```js + /// default myArray: array = {"item1", "item2", "item3"}; + /// ``` + fn visit_array_initializer_expr(&mut self, n: &ArrayInitializerExpressionNode, ctx: &TraversalContextStack) -> ArrayInitializerExpressionTraversalPolicy { TraversalPolicy::default_to(self.traversal_policy_default()) } + /// Called after visiting an array initializer expression and possibly also children nodes specified in traversal policy. + fn exit_array_initializer_expr(&mut self, n: &ArrayInitializerExpressionNode, ctx: &TraversalContextStack) {} + diff --git a/crates/core/src/ast/traversal/visitor_chain.rs b/crates/core/src/ast/traversal/visitor_chain.rs index 2a0a7970..4cf4ba93 100644 --- a/crates/core/src/ast/traversal/visitor_chain.rs +++ b/crates/core/src/ast/traversal/visitor_chain.rs @@ -549,6 +549,16 @@ impl<'a> SyntaxNodeVisitor for SyntaxNodeVisitorChain<'a> { self.chain_visit(move |link| link.visit_virtual_parent_expr(n, ctx)) } + #[inline] + fn visit_array_initializer_expr(&mut self, n: &ArrayInitializerExpressionNode, ctx: &TraversalContextStack) -> ArrayInitializerExpressionTraversalPolicy { + self.chain_visit_traversable(move |link| link.visit_array_initializer_expr(n, ctx)) + } + + #[inline] + fn exit_array_initializer_expr(&mut self, n: &ArrayInitializerExpressionNode, ctx: &TraversalContextStack) { + self.chain_exit(move |link| link.exit_array_initializer_expr(n, ctx)) + } + #[inline] fn visit_annotation(&mut self, n: &AnnotationNode, ctx: &TraversalContextStack) -> AnnotationTraversalPolicy { diff --git a/crates/core/src/script.rs b/crates/core/src/script.rs index 1630902a..fd7f2684 100644 --- a/crates/core/src/script.rs +++ b/crates/core/src/script.rs @@ -59,7 +59,7 @@ impl Script { use ScriptError::*; let mut parser = Parser::new(); - parser.set_language(tree_sitter_witcherscript::language()).map_err(ParserInitError)?; + parser.set_language(&tree_sitter_witcherscript::language()).map_err(ParserInitError)?; let parse_tree = parser.parse_with(&mut |byte, _| { if byte <= rope.len_bytes() { diff --git a/crates/core/src/syntax_node.rs b/crates/core/src/syntax_node.rs index 93d0c19b..14869a6e 100644 --- a/crates/core/src/syntax_node.rs +++ b/crates/core/src/syntax_node.rs @@ -336,7 +336,7 @@ impl<'script> Iterator for SyntaxNodeChildren<'script> { pub struct SyntaxNodeFieldChildren<'script> { cursor: ts::TreeCursor<'script>, any_children_left: bool, - field_id: u16 + field_id: std::num::NonZeroU16 } impl<'script> SyntaxNodeFieldChildren<'script> { @@ -344,7 +344,7 @@ impl<'script> SyntaxNodeFieldChildren<'script> { let mut cursor = cursor.unwrap_or(tree_node.walk()); let any_children_left = cursor.goto_first_child(); - let field_id = tree_sitter_witcherscript::language() + let field_id = tree_node.language() .field_id_for_name(field_name) .expect(&format!("Unknown field name {}", field_name)); diff --git a/crates/core/src/syntax_node_any.rs b/crates/core/src/syntax_node_any.rs index 9a751926..2e482143 100644 --- a/crates/core/src/syntax_node_any.rs +++ b/crates/core/src/syntax_node_any.rs @@ -46,6 +46,7 @@ impl<'script> SyntaxNodeTraversal for AnyNode<'script> { BinaryOperationExpressionNode::NODE_KIND => { let n: BinaryOperationExpressionNode = n.unsafe_into(); n.accept(visitor, ctx); }, AssignmentOperationExpressionNode::NODE_KIND => { let n: AssignmentOperationExpressionNode = n.unsafe_into(); n.accept(visitor, ctx); }, TernaryConditionalExpressionNode::NODE_KIND => { let n: TernaryConditionalExpressionNode = n.unsafe_into(); n.accept(visitor, ctx); }, + ArrayInitializerExpressionNode::NODE_KIND => { let n: ArrayInitializerExpressionNode = n.unsafe_into(); n.accept(visitor, ctx); }, RootNode::NODE_KIND => { let n: RootNode = n.unsafe_into(); n.accept(visitor, ctx); },