diff --git a/src/GDShrapt.Reader.Tests/SyntaxTests.cs b/src/GDShrapt.Reader.Tests/SyntaxTests.cs
index 6f42ab0..7cbb570 100644
--- a/src/GDShrapt.Reader.Tests/SyntaxTests.cs
+++ b/src/GDShrapt.Reader.Tests/SyntaxTests.cs
@@ -1,6 +1,7 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
+using System.Xml.Linq;
namespace GDShrapt.Reader.Tests
{
@@ -414,5 +415,51 @@ func _process(delta) -> void:
AssertHelper.CompareCodeStrings(code, @class.ToString());
AssertHelper.NoInvalidTokens(@class);
}
+
+ [TestMethod]
+ public void AttributesDeclaredBeforeTest()
+ {
+ var reader = new GDScriptReader();
+
+ var code = @"
+@tool
+@static_unload
+class_name MyClass extends Node
+@export var a = ""Hello""
+@onready @export var b = ""init_value_b""";
+
+ var @class = reader.ParseFileContent(code);
+
+ var members = @class.Members.ToArray();
+
+ Assert.AreEqual(9, members.Length);
+
+ members[8].AttributesDeclaredBefore.Select(x => x.ToString()).Should().BeEquivalentTo(new[]
+ {
+ "@export ",
+ "@onready "
+ });
+
+ members[8].AttributesDeclaredBeforeFromStartOfTheClass.Select(x => x.ToString()).Should().BeEquivalentTo(new[]
+ {
+ "@export ",
+ "@onready ",
+ "@export ",
+ "@static_unload",
+ "@tool"
+ });
+
+ members[5].AttributesDeclaredBeforeFromStartOfTheClass.Select(x => x.ToString()).Should().BeEquivalentTo(new[]
+ {
+ "@export ",
+ "@static_unload",
+ "@tool"
+ });
+
+ members[5].AttributesDeclaredBefore.Select(x => x.ToString()).Should().BeEquivalentTo(new[]
+ {
+ "@export "
+ });
+ }
}
}
diff --git a/src/GDShrapt.Reader/Basics/GDNode.cs b/src/GDShrapt.Reader/Basics/GDNode.cs
index addd2b9..f37c07f 100644
--- a/src/GDShrapt.Reader/Basics/GDNode.cs
+++ b/src/GDShrapt.Reader/Basics/GDNode.cs
@@ -8,7 +8,7 @@ namespace GDShrapt.Reader
///
/// Basic GDScript node, may contains multiple tokens
///
- public abstract class GDNode : GDSyntaxToken,
+ public abstract class GDNode : GDSyntaxToken, IGDNode,
ITokenReceiver,
ITokenReceiver
{
@@ -21,7 +21,6 @@ public GDSyntaxToken[] FormTokensSetter
{
set => Form.SetFormUnsafe(value);
}
-
public IEnumerable Tokens => Form.Direct();
public IEnumerable TokensReversed => Form.Reversed();
diff --git a/src/GDShrapt.Reader/Basics/IGDClassDeclaration.cs b/src/GDShrapt.Reader/Basics/IGDClassDeclaration.cs
index 2213972..778dde8 100644
--- a/src/GDShrapt.Reader/Basics/IGDClassDeclaration.cs
+++ b/src/GDShrapt.Reader/Basics/IGDClassDeclaration.cs
@@ -2,7 +2,7 @@
namespace GDShrapt.Reader
{
- public interface IGDClassDeclaration : IGDSyntaxToken
+ public interface IGDClassDeclaration : IGDNode
{
GDIdentifier Identifier { get; }
GDClassMembersList Members { get; }
@@ -13,5 +13,6 @@ public interface IGDClassDeclaration : IGDSyntaxToken
IEnumerable Enums { get; }
IEnumerable InnerClasses { get; }
IEnumerable IdentifiableMembers { get; }
+ IEnumerable CustomAttributes { get; }
}
}
diff --git a/src/GDShrapt.Reader/Basics/IGDNode.cs b/src/GDShrapt.Reader/Basics/IGDNode.cs
new file mode 100644
index 0000000..e90b120
--- /dev/null
+++ b/src/GDShrapt.Reader/Basics/IGDNode.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+
+namespace GDShrapt.Reader
+{
+ public interface IGDNode : IGDSyntaxToken
+ {
+ IEnumerable Nodes { get; }
+ IEnumerable NodesReversed { get; }
+ IEnumerable AllNodes { get; }
+ IEnumerable AllNodesReversed { get; }
+ IEnumerable AllTokens { get; }
+ IEnumerable AllTokensReversed { get; }
+
+ int TokensCount { get; }
+ bool HasTokens { get; }
+ GDTokensForm Form { get; }
+ GDSyntaxToken[] FormTokensSetter { set; }
+
+ void UpdateIntendation();
+ }
+}
diff --git a/src/GDShrapt.Reader/Declarations/Class/GDClassMember.cs b/src/GDShrapt.Reader/Declarations/Class/GDClassMember.cs
index 3f3dcf9..994008d 100644
--- a/src/GDShrapt.Reader/Declarations/Class/GDClassMember.cs
+++ b/src/GDShrapt.Reader/Declarations/Class/GDClassMember.cs
@@ -1,8 +1,10 @@
-namespace GDShrapt.Reader
+using System.Collections.Generic;
+
+namespace GDShrapt.Reader
{
public abstract class GDClassMember : GDIntendedNode
{
- internal GDClassMember(int intendation)
+ internal GDClassMember(int intendation)
: base(intendation)
{
}
@@ -11,5 +13,62 @@ internal GDClassMember()
: base()
{
}
+
+ public IEnumerable AttributesDeclaredBefore
+ {
+ get
+ {
+ var @class = ClassDeclaration;
+
+ if (@class == null)
+ yield break;
+
+ bool foundThis = false;
+
+ foreach (var item in @class.Members.NodesReversed)
+ {
+ if (!foundThis)
+ {
+ if (ReferenceEquals(item, this))
+ foundThis = true;
+ }
+ else
+ {
+ if (item is GDCustomAttribute attr)
+ yield return attr;
+ else
+ yield break;
+
+ }
+ }
+ }
+ }
+
+ public IEnumerable AttributesDeclaredBeforeFromStartOfTheClass
+ {
+ get
+ {
+ var @class = ClassDeclaration;
+
+ if (@class == null)
+ yield break;
+
+ bool foundThis = false;
+
+ foreach (var item in @class.Members.NodesReversed)
+ {
+ if (!foundThis)
+ {
+ if (ReferenceEquals(item, this))
+ foundThis = true;
+ }
+ else
+ {
+ if (item is GDCustomAttribute attr)
+ yield return attr;
+ }
+ }
+ }
+ }
}
}
diff --git a/src/GDShrapt.Reader/Declarations/GDClassDeclaration.cs b/src/GDShrapt.Reader/Declarations/GDClassDeclaration.cs
index beea458..ddfc9d3 100644
--- a/src/GDShrapt.Reader/Declarations/GDClassDeclaration.cs
+++ b/src/GDShrapt.Reader/Declarations/GDClassDeclaration.cs
@@ -35,6 +35,8 @@ public GDClassDeclaration()
public bool IsTool => Attributes.OfType().Any();
public IEnumerable Attributes => Members.OfType();
+ public IEnumerable CustomAttributes => Members.OfType();
+
public IEnumerable Variables => Members.OfType();
public IEnumerable Methods => Members.OfType();
public IEnumerable Enums => Members.OfType();
diff --git a/src/GDShrapt.Reader/Declarations/GDInnerClassDeclaration.cs b/src/GDShrapt.Reader/Declarations/GDInnerClassDeclaration.cs
index b3b61f2..d923e8e 100644
--- a/src/GDShrapt.Reader/Declarations/GDInnerClassDeclaration.cs
+++ b/src/GDShrapt.Reader/Declarations/GDInnerClassDeclaration.cs
@@ -16,6 +16,7 @@ public sealed class GDInnerClassDeclaration : GDIdentifiableClassMember, IGDClas
public IEnumerable Enums => Members.OfType();
public IEnumerable InnerClasses => Members.OfType();
public IEnumerable IdentifiableMembers => Members.OfType();
+ public IEnumerable CustomAttributes => Members.OfType();
public GDClassKeyword ClassKeyword
{