284 lines
8.2 KiB
Rust
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>>,
|
|
}
|