// `;` are encoded in spans of statement nodes as very last token // Need to do a proper check to figure out what should and shouldn't be a node use crate::arena::ArenaVec; use super::lexer::{TokenPosition, TokenSpan}; use crate::arena::{Arena, ArenaNode, ArenaString}; pub mod callables; pub mod expressions; pub mod operators; pub mod types; pub use callables::*; pub use expressions::*; pub use operators::*; pub use types::*; // Get rid of identifier field #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub struct IdentifierToken(pub TokenPosition); #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub struct OperatorToken(pub TokenPosition); #[derive(Debug, Hash, PartialEq, Eq)] pub struct QualifiedIdentifier<'arena> { pub head: IdentifierToken, pub tail: Option>, // None => single segment } pub type QualifiedIdentifierRef<'arena> = ArenaNode<'arena, QualifiedIdentifier<'arena>>; impl<'arena> QualifiedIdentifier<'arena> { #[inline] #[must_use] pub const fn is_single(&self) -> bool { self.tail.is_none() } #[inline] #[allow(clippy::len_without_is_empty)] // Suppress useless suggestion for `is_empty()` #[must_use] pub fn len(&self) -> usize { 1 + self.tail.as_ref().map_or(0, |v| v.len()) } #[inline] #[must_use] pub const fn head(&self) -> IdentifierToken { self.head } /// Iterates all identifier segments in order without allocating. pub fn iter(&self) -> impl Iterator + '_ { core::iter::once(self.head).chain(self.tail.iter().flat_map(|v| v.iter().copied())) } /// Cheap constructor from a single identifier. No Vec allocated. pub fn from_ident(arena: &'arena Arena, id: IdentifierToken) -> QualifiedIdentifierRef<'arena> { let span = TokenSpan::new(id.0); ArenaNode::new_in( Self { head: id, tail: None, }, span, arena, ) } /// Cheap constructor from a single identifier. No Vec allocated. pub fn from_position( arena: &'arena Arena, position: TokenPosition, ) -> QualifiedIdentifierRef<'arena> { let span = TokenSpan::new(position); ArenaNode::new_in( Self { head: IdentifierToken(position), tail: None, }, span, arena, ) } } #[derive(Debug, PartialEq)] pub enum Statement<'src, 'arena> { // For the cases where user just used too many semi-colons `;;;;` Empty, Expression(ExpressionRef<'src, 'arena>), // Just declarations without assignment: // `local int i, j, k` LocalVariableDeclaration { type_spec: TypeSpecifierRef<'src, 'arena>, declarators: ArenaVec<'arena, VariableDeclaratorRef<'src, 'arena>>, // CHANGED }, Label(ArenaString<'arena>), /// Nested function definitions inside blocks or states. Function(CallableDefinitionRef<'src, 'arena>), // For injecting in place of parts that couldn't be parsed Error, } pub type StatementRef<'src, 'arena> = ArenaNode<'arena, Statement<'src, 'arena>>; #[derive(Debug)] pub enum DeclarationLiteral<'src, 'arena> { None, Bool(bool), Integer(i128), Float(f64), String(ArenaString<'arena>), Identifier(&'src str), TaggedName { tag: IdentifierToken, quoted: ArenaString<'arena>, }, // NEW } #[derive(Debug)] pub struct DeclarationLiteralRef<'src, 'arena> { pub literal: DeclarationLiteral<'src, 'arena>, pub position: TokenPosition, } impl IdentifierToken { #[must_use] pub const fn span(self) -> TokenSpan { TokenSpan::new(self.0) } } pub enum ClassModifier<'arena> { Final, Native, Abstract, Transient, Public, Protected, Private, Static, Config(Option), NativeReplication, ExportStructs, SafeReplace, Const, Deprecated, NoExport, Export, Localized, Placeable, NotPlaceable, Instanced, EditConst, EditInline, EditInlineNew, NotEditInlineNew, CollapseCategories, DontCollapseCategories, HideCategories(ArenaVec<'arena, IdentifierToken>), ShowCategories(ArenaVec<'arena, IdentifierToken>), Within(IdentifierToken), DependsOn(IdentifierToken), GlobalConfig, PerObjectConfig, DynamicRecompile, HideDropdown, ParseConfig, CacheExempt, } pub type ClassModifierRef<'arena> = ArenaNode<'arena, ClassModifier<'arena>>; pub struct ClassDeclaration<'arena> { pub name: IdentifierToken, pub parent: Option, pub modifiers: Vec>, } // --- in ast.rs --- #[derive(Debug)] pub struct ClassVarDecl<'src, 'arena> { /// var(<...>) e.g. var(Display, "Advanced") /// Each item is an `ArenaNode`, so token locations are preserved. pub paren_specs: Option>>, /// variable modifiers like public/protected/private/static/const/... /// Each modifier is an `ArenaNode` capturing its span; order preserved. pub modifiers: ArenaVec<'arena, VarModifier>, pub type_spec: TypeSpecifierRef<'src, 'arena>, // Named/InlineEnum/InlineStruct pub declarators: ArenaVec<'arena, VariableDeclaratorRef<'src, 'arena>>, // a, b=expr pub span: TokenSpan, } pub type ClassVarDeclRef<'src, 'arena> = ArenaNode<'arena, ClassVarDecl<'src, 'arena>>; #[derive(Debug)] pub struct ClassConstDecl<'src, 'arena> { pub name: IdentifierToken, pub value: DeclarationLiteralRef<'src, 'arena>, pub span: TokenSpan, } pub type ClassConstDeclRef<'src, 'arena> = ArenaNode<'arena, ClassConstDecl<'src, 'arena>>; pub enum ClassMember<'src, 'arena> where 'src: 'arena, { Function(CallableDefinitionRef<'src, 'arena>), TypeDefEnum(EnumDefRef<'src, 'arena>), TypeDefStruct(StructDefRef<'src, 'arena>), Var(ClassVarDeclRef<'src, 'arena>), Replication(ReplicationBlockRef<'src, 'arena>), State(StateDeclRef<'src, 'arena>), Const(ClassConstDeclRef<'src, 'arena>), Exec(ExecDirectiveRef<'arena>), } pub type ClassMemberRef<'src, 'arena> = ArenaNode<'arena, ClassMember<'src, 'arena>>; #[derive(Clone, Copy, Debug)] pub enum Reliability { Reliable, Unreliable, } #[derive(Debug)] pub struct ReplicationRule<'src, 'arena> { pub reliability: Reliability, // reliable|unreliable pub condition: Option>, // if () or None pub members: ArenaVec<'arena, IdentifierToken>, // a, b, Foo() pub span: TokenSpan, } pub type ReplicationRuleRef<'src, 'arena> = ArenaNode<'arena, ReplicationRule<'src, 'arena>>; #[derive(Debug)] pub struct ReplicationBlock<'src, 'arena> { pub rules: ArenaVec<'arena, ReplicationRuleRef<'src, 'arena>>, pub span: TokenSpan, } pub type ReplicationBlockRef<'src, 'arena> = ArenaNode<'arena, ReplicationBlock<'src, 'arena>>; // ---------- States ---------- #[derive(Clone, Copy, Debug)] pub enum StateModifier { Auto, // 'auto' Simulated, // 'simulated' } #[derive(Debug)] pub struct StateDecl<'src, 'arena> { pub name: IdentifierToken, pub parent: Option, // 'extends BaseState' pub modifiers: ArenaVec<'arena, StateModifier>, // auto, simulated pub ignores: Option>, // 'ignores Foo, Bar;' /// Body: ordinary statements plus nested function definitions (see `Statement::Function`). pub body: ArenaVec<'arena, StatementRef<'src, 'arena>>, pub span: TokenSpan, } pub type StateDeclRef<'src, 'arena> = ArenaNode<'arena, StateDecl<'src, 'arena>>; // NEW: exec directive node #[derive(Debug)] pub struct ExecDirective<'arena> { pub text: ArenaString<'arena>, // full line without trailing newline(s) pub span: TokenSpan, } pub type ExecDirectiveRef<'arena> = ArenaNode<'arena, ExecDirective<'arena>>; /// Keep your existing `ClassDeclaration` as the header. /// Optionally: `pub type ClassHeader<'src, 'arena> = ClassDeclaration<'src, 'arena>;` pub struct ClassDefinition<'src, 'arena> where 'src: 'arena, { pub header: ClassDeclaration<'arena>, // or ClassHeader if you rename pub members: ArenaVec<'arena, ClassMemberRef<'src, 'arena>>, }