rott/rottlib/src/ast/mod.rs

284 lines
8.2 KiB
Rust

// `;` 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<ArenaVec<'arena, IdentifierToken>>, // 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<Item = IdentifierToken> + '_ {
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<IdentifierToken>),
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<IdentifierToken>,
pub modifiers: Vec<ClassModifierRef<'arena>>,
}
// --- 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<ArenaVec<'arena, VarEditorSpecifierRef<'src, 'arena>>>,
/// 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<ExpressionRef<'src, 'arena>>, // if (<expr>) 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<IdentifierToken>, // 'extends BaseState'
pub modifiers: ArenaVec<'arena, StateModifier>, // auto, simulated
pub ignores: Option<ArenaVec<'arena, IdentifierToken>>, // '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>>,
}