rott/rottlib/src/lexer/token.rs
dkanus 588790b9b4 Refactor everything
Huge dump of refactored code. Still in the middle of the changes that
are to be squashed later in a one huge monster commit, because there is
no value in anything atomic here.
2026-04-05 20:32:11 +07:00

561 lines
19 KiB
Rust

//! Token definitions for Fermented `UnrealScript`.
//!
//! These are the tokens consumed by the parser and derived from [`RawToken`]s.
use super::{BraceKind, raw_lexer::RawToken};
/// Tokens consumed by the Fermented `UnrealScript` parser.
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum Token {
ExecDirective,
Keyword(Keyword),
// Primaries
FloatLiteral,
IntegerLiteral,
StringLiteral,
NameLiteral,
Identifier,
// Operations
Exponentiation,
Increment,
Decrement,
Not,
BitwiseNot,
Multiply,
Divide,
Modulo,
Plus,
Minus,
ConcatSpace,
Concat,
LeftShift,
LogicalRightShift,
RightShift,
Less,
LessEqual,
Greater,
GreaterEqual,
Equal,
NotEqual,
ApproximatelyEqual,
BitwiseAnd,
BitwiseOr,
BitwiseXor,
LogicalAnd,
LogicalXor,
LogicalOr,
Assign,
MultiplyAssign,
DivideAssign,
ModuloAssign,
PlusAssign,
MinusAssign,
ConcatAssign,
ConcatSpaceAssign,
// Delimiters
LeftParenthesis,
RightParenthesis,
LeftBrace,
CppBlock,
RightBrace,
LeftBracket,
RightBracket,
Semicolon,
Comma,
Period,
Colon,
Hash,
Question,
// Trivia
LineComment,
BlockComment,
Newline,
Whitespace,
// Technical - for representing a very wrong sequence of characters
Error,
}
impl From<RawToken> for Token {
#![allow(clippy::too_many_lines)]
fn from(token: RawToken) -> Self {
match token {
// Non-trivial conversions
RawToken::Brace(BraceKind::Normal) => Self::LeftBrace,
RawToken::Brace(BraceKind::CppBlock) => Self::CppBlock,
// Keyword conversions
RawToken::CppText => Self::Keyword(Keyword::CppText),
RawToken::CppStruct => Self::Keyword(Keyword::CppStruct),
RawToken::Class => Self::Keyword(Keyword::Class),
RawToken::Struct => Self::Keyword(Keyword::Struct),
RawToken::Enum => Self::Keyword(Keyword::Enum),
RawToken::State => Self::Keyword(Keyword::State),
RawToken::Auto => Self::Keyword(Keyword::Auto),
RawToken::Function => Self::Keyword(Keyword::Function),
RawToken::Event => Self::Keyword(Keyword::Event),
RawToken::Delegate => Self::Keyword(Keyword::Delegate),
RawToken::Var => Self::Keyword(Keyword::Var),
RawToken::Local => Self::Keyword(Keyword::Local),
RawToken::Extends => Self::Keyword(Keyword::Extends),
RawToken::DependsOn => Self::Keyword(Keyword::DependsOn),
RawToken::Private => Self::Keyword(Keyword::Private),
RawToken::Protected => Self::Keyword(Keyword::Protected),
RawToken::Public => Self::Keyword(Keyword::Public),
RawToken::Const => Self::Keyword(Keyword::Const),
RawToken::Static => Self::Keyword(Keyword::Static),
RawToken::Native => Self::Keyword(Keyword::Native),
RawToken::Abstract => Self::Keyword(Keyword::Abstract),
RawToken::Deprecated => Self::Keyword(Keyword::Deprecated),
RawToken::SafeReplace => Self::Keyword(Keyword::SafeReplace),
RawToken::ExportStructs => Self::Keyword(Keyword::ExportStructs),
RawToken::Input => Self::Keyword(Keyword::Input),
RawToken::Final => Self::Keyword(Keyword::Final),
RawToken::Default => Self::Keyword(Keyword::Default),
RawToken::DefaultProperties => Self::Keyword(Keyword::DefaultProperties),
RawToken::Object => Self::Keyword(Keyword::Object),
RawToken::Begin => Self::Keyword(Keyword::Begin),
RawToken::End => Self::Keyword(Keyword::End),
RawToken::Optional => Self::Keyword(Keyword::Optional),
RawToken::Config => Self::Keyword(Keyword::Config),
RawToken::PerObjectConfig => Self::Keyword(Keyword::PerObjectConfig),
RawToken::GlobalConfig => Self::Keyword(Keyword::GlobalConfig),
RawToken::CollapseCategories => Self::Keyword(Keyword::CollapseCategories),
RawToken::DontCollapseCategories => Self::Keyword(Keyword::DontCollapseCategories),
RawToken::HideCategories => Self::Keyword(Keyword::HideCategories),
RawToken::ShowCategories => Self::Keyword(Keyword::ShowCategories),
RawToken::Localized => Self::Keyword(Keyword::Localized),
RawToken::Placeable => Self::Keyword(Keyword::Placeable),
RawToken::NotPlaceable => Self::Keyword(Keyword::NotPlaceable),
RawToken::Instanced => Self::Keyword(Keyword::Instanced),
RawToken::EditConst => Self::Keyword(Keyword::EditConst),
RawToken::EditConstArray => Self::Keyword(Keyword::EditConstArray),
RawToken::EditInline => Self::Keyword(Keyword::EditInline),
RawToken::EditInlineUse => Self::Keyword(Keyword::EditInlineUse),
RawToken::EditInlineNew => Self::Keyword(Keyword::EditInlineNew),
RawToken::NotEditInlineNew => Self::Keyword(Keyword::NotEditInlineNew),
RawToken::EdFindable => Self::Keyword(Keyword::EdFindable),
RawToken::EditInlineNotify => Self::Keyword(Keyword::EditInlineNotify),
RawToken::ParseConfig => Self::Keyword(Keyword::ParseConfig),
RawToken::Automated => Self::Keyword(Keyword::Automated),
RawToken::DynamicRecompile => Self::Keyword(Keyword::DynamicRecompile),
RawToken::Transient => Self::Keyword(Keyword::Transient),
RawToken::Long => Self::Keyword(Keyword::Long),
RawToken::Operator => Self::Keyword(Keyword::Operator),
RawToken::PreOperator => Self::Keyword(Keyword::PreOperator),
RawToken::PostOperator => Self::Keyword(Keyword::PostOperator),
RawToken::Simulated => Self::Keyword(Keyword::Simulated),
RawToken::Exec => Self::Keyword(Keyword::Exec),
RawToken::Latent => Self::Keyword(Keyword::Latent),
RawToken::Iterator => Self::Keyword(Keyword::Iterator),
RawToken::Out => Self::Keyword(Keyword::Out),
RawToken::Skip => Self::Keyword(Keyword::Skip),
RawToken::Singular => Self::Keyword(Keyword::Singular),
RawToken::Coerce => Self::Keyword(Keyword::Coerce),
RawToken::Assert => Self::Keyword(Keyword::Assert),
RawToken::Ignores => Self::Keyword(Keyword::Ignores),
RawToken::Within => Self::Keyword(Keyword::Within),
RawToken::Init => Self::Keyword(Keyword::Init),
RawToken::Export => Self::Keyword(Keyword::Export),
RawToken::NoExport => Self::Keyword(Keyword::NoExport),
RawToken::HideDropdown => Self::Keyword(Keyword::HideDropdown),
RawToken::Travel => Self::Keyword(Keyword::Travel),
RawToken::Cache => Self::Keyword(Keyword::Cache),
RawToken::CacheExempt => Self::Keyword(Keyword::CacheExempt),
RawToken::Reliable => Self::Keyword(Keyword::Reliable),
RawToken::Unreliable => Self::Keyword(Keyword::Unreliable),
RawToken::Replication => Self::Keyword(Keyword::Replication),
RawToken::NativeReplication => Self::Keyword(Keyword::NativeReplication),
RawToken::Goto => Self::Keyword(Keyword::Goto),
RawToken::If => Self::Keyword(Keyword::If),
RawToken::Else => Self::Keyword(Keyword::Else),
RawToken::Switch => Self::Keyword(Keyword::Switch),
RawToken::Case => Self::Keyword(Keyword::Case),
RawToken::For => Self::Keyword(Keyword::For),
RawToken::ForEach => Self::Keyword(Keyword::ForEach),
RawToken::While => Self::Keyword(Keyword::While),
RawToken::Do => Self::Keyword(Keyword::Do),
RawToken::Until => Self::Keyword(Keyword::Until),
RawToken::Break => Self::Keyword(Keyword::Break),
RawToken::Continue => Self::Keyword(Keyword::Continue),
RawToken::Return => Self::Keyword(Keyword::Return),
RawToken::Int => Self::Keyword(Keyword::Int),
RawToken::Float => Self::Keyword(Keyword::Float),
RawToken::Bool => Self::Keyword(Keyword::Bool),
RawToken::Byte => Self::Keyword(Keyword::Byte),
RawToken::String => Self::Keyword(Keyword::String),
RawToken::Array => Self::Keyword(Keyword::Array),
RawToken::Name => Self::Keyword(Keyword::Name),
RawToken::True => Self::Keyword(Keyword::True),
RawToken::False => Self::Keyword(Keyword::False),
RawToken::None => Self::Keyword(Keyword::None),
RawToken::SelfValue => Self::Keyword(Keyword::SelfValue),
RawToken::New => Self::Keyword(Keyword::New),
RawToken::Dot => Self::Keyword(Keyword::Dot),
RawToken::Cross => Self::Keyword(Keyword::Cross),
RawToken::ClockwiseFrom => Self::Keyword(Keyword::ClockwiseFrom),
// Trivial 1-to-1 conversions.
RawToken::ExecDirective => Self::ExecDirective,
RawToken::FloatLiteral => Self::FloatLiteral,
RawToken::IntegerLiteral => Self::IntegerLiteral,
RawToken::StringLiteral => Self::StringLiteral,
RawToken::NameLiteral => Self::NameLiteral,
RawToken::Identifier => Self::Identifier,
RawToken::Exponentiation => Self::Exponentiation,
RawToken::Increment => Self::Increment,
RawToken::Decrement => Self::Decrement,
RawToken::Not => Self::Not,
RawToken::BitwiseNot => Self::BitwiseNot,
RawToken::Multiply => Self::Multiply,
RawToken::Divide => Self::Divide,
RawToken::Modulo => Self::Modulo,
RawToken::Plus => Self::Plus,
RawToken::Minus => Self::Minus,
RawToken::ConcatSpace => Self::ConcatSpace,
RawToken::Concat => Self::Concat,
RawToken::LeftShift => Self::LeftShift,
RawToken::LogicalRightShift => Self::LogicalRightShift,
RawToken::RightShift => Self::RightShift,
RawToken::Less => Self::Less,
RawToken::LessEqual => Self::LessEqual,
RawToken::Greater => Self::Greater,
RawToken::GreaterEqual => Self::GreaterEqual,
RawToken::Equal => Self::Equal,
RawToken::NotEqual => Self::NotEqual,
RawToken::ApproximatelyEqual => Self::ApproximatelyEqual,
RawToken::BitwiseAnd => Self::BitwiseAnd,
RawToken::BitwiseOr => Self::BitwiseOr,
RawToken::BitwiseXor => Self::BitwiseXor,
RawToken::LogicalAnd => Self::LogicalAnd,
RawToken::LogicalXor => Self::LogicalXor,
RawToken::LogicalOr => Self::LogicalOr,
RawToken::Assign => Self::Assign,
RawToken::MultiplyAssign => Self::MultiplyAssign,
RawToken::DivideAssign => Self::DivideAssign,
RawToken::ModuloAssign => Self::ModuloAssign,
RawToken::PlusAssign => Self::PlusAssign,
RawToken::MinusAssign => Self::MinusAssign,
RawToken::ConcatAssign => Self::ConcatAssign,
RawToken::ConcatSpaceAssign => Self::ConcatSpaceAssign,
RawToken::LeftParenthesis => Self::LeftParenthesis,
RawToken::RightParenthesis => Self::RightParenthesis,
RawToken::RightBrace => Self::RightBrace,
RawToken::LeftBracket => Self::LeftBracket,
RawToken::RightBracket => Self::RightBracket,
RawToken::Semicolon => Self::Semicolon,
RawToken::Comma => Self::Comma,
RawToken::Period => Self::Period,
RawToken::Colon => Self::Colon,
RawToken::Hash => Self::Hash,
RawToken::Question => Self::Question,
RawToken::LineComment => Self::LineComment,
RawToken::BlockComment => Self::BlockComment,
RawToken::Newline => Self::Newline,
RawToken::Whitespace => Self::Whitespace,
RawToken::Error => Self::Error,
}
}
}
impl Token {
/// Returns `true` if this token is a newline.
#[must_use]
pub const fn is_newline(&self) -> bool {
matches!(self, Self::Newline)
}
/// Returns `true` if this token is trivia whitespace.
///
/// Note: comments are **not** considered whitespace.
#[must_use]
pub const fn is_whitespace(&self) -> bool {
matches!(self, Self::Whitespace | Self::Newline)
}
/// Returns `true` if this token may span multiple physical lines
/// (i.e. can contain newline characters).
#[must_use]
pub const fn can_span_lines(&self) -> bool {
matches!(self, Self::BlockComment | Self::CppBlock | Self::Error)
}
/// Returns `true` if this token can appear in type position
/// (either a built-in type keyword or an identifier).
#[must_use]
pub fn is_valid_type_name(&self) -> bool {
let Self::Keyword(keyword) = self else {
return *self == Self::Identifier;
};
keyword.is_valid_type_name()
}
/// Returns `true` if this token can be used as an identifier.
///
/// This includes [`Token::Identifier`] and certain keywords that
/// `UnrealScript` also accepts in identifier position.
#[must_use]
pub fn is_valid_identifier_name(&self) -> bool {
if *self == Self::Identifier {
return true;
}
if let Self::Keyword(keyword) = self {
return keyword.is_valid_identifier_name();
}
false
}
/// Returns `true` if this token can be used as function's modifier.
#[must_use]
pub const fn is_valid_function_modifier(&self) -> bool {
let Self::Keyword(keyword) = self else {
return false;
};
matches!(
keyword,
Keyword::Final
| Keyword::Native
| Keyword::Abstract
| Keyword::Transient
| Keyword::Public
| Keyword::Protected
| Keyword::Private
| Keyword::Static
| Keyword::Const
| Keyword::Deprecated
| Keyword::NoExport
| Keyword::Export
| Keyword::Simulated
| Keyword::Latent
| Keyword::Iterator
| Keyword::Singular
| Keyword::Reliable
| Keyword::Unreliable
| Keyword::NativeReplication
| Keyword::PreOperator
| Keyword::Operator
| Keyword::PostOperator
| Keyword::Config
| Keyword::Exec
)
}
}
/// Reserved words of Fermented `UnrealScript`.
///
/// These are represented in [`Token`] as [`Token::Keyword`].
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum Keyword {
// C++ blocks
CppText,
CppStruct,
// Top-level declaration
Class,
Struct,
Enum,
State,
Auto,
Function,
Event,
Delegate,
Var,
Local,
// Class modifiers
Extends,
DependsOn,
// Access modifiers
Private,
Protected,
Public,
Const,
// Meta data / specifiers
Static,
Native,
Abstract,
Deprecated,
SafeReplace,
ExportStructs,
Input,
Final,
Default,
DefaultProperties,
Object,
Begin,
End,
Optional,
Config,
PerObjectConfig,
GlobalConfig,
CollapseCategories,
DontCollapseCategories,
HideCategories,
ShowCategories,
Localized,
Placeable,
NotPlaceable,
Instanced,
EditConst,
EditConstArray,
EditInline,
EditInlineUse,
EditInlineNew,
NotEditInlineNew,
EdFindable,
EditInlineNotify,
ParseConfig,
Automated,
DynamicRecompile,
Transient,
Long,
Operator,
PreOperator,
PostOperator,
Simulated,
Exec,
Latent,
Iterator,
Out,
Skip,
Singular,
Coerce,
Assert,
Ignores,
Within,
Init,
Export,
NoExport,
HideDropdown,
Travel,
Cache,
CacheExempt,
// Replication
Reliable,
Unreliable,
Replication,
NativeReplication,
// Control flow
Goto,
If,
Else,
Switch,
Case,
For,
ForEach,
While,
Do,
Until,
Break,
Continue,
Return,
// Built-in types
Int,
Float,
Bool,
Byte,
String,
Array,
Name,
// Literals
True,
False,
None,
SelfValue,
New,
// Vector math operators
Dot,
Cross,
ClockwiseFrom,
}
impl Keyword {
/// Returns `true` if this keyword can be used as an identifier.
#[must_use]
pub const fn is_valid_identifier_name(self) -> bool {
matches!(
self,
// Built-in type words usable as identifiers
Self::Name
| Self::String
| Self::Byte
| Self::Int
| Self::Bool
| Self::Float
| Self::Array
| Self::Delegate
// Context keywords we've directly checked
| Self::Class
| Self::SelfValue
| Self::Default
| Self::Static
| Self::Simulated
| Self::Native
| Self::Latent
| Self::Iterator
| Self::Singular
| Self::Reliable
| Self::Unreliable
| Self::Transient
| Self::Const
| Self::Abstract
| Self::New
| Self::Extends
| Self::Within
| Self::Config
| Self::Out
| Self::Optional
| Self::Local
| Self::Var
| Self::DefaultProperties
| Self::PerObjectConfig
| Self::Object
| Self::Enum
| Self::End
| Self::Event
| Self::Switch
| Self::Goto
| Self::Cross
| Self::CppText
| Self::CppStruct
| Self::HideCategories
| Self::Auto
| Self::For
| Self::Skip
| Self::Placeable
| Self::NotPlaceable
| Self::Instanced
| Self::Function
| Self::State
| Self::Init
| Self::Export
| Self::NoExport
| Self::Dot
| Self::ClockwiseFrom
| Self::Assert
| Self::ExportStructs
| Self::SafeReplace
| Self::Input
| Self::Travel
| Self::Cache
| Self::CacheExempt
| Self::Long
| Self::Continue
)
}
/// Returns `true` if this keyword can appear in type position.
#[must_use]
pub const fn is_valid_type_name(self) -> bool {
matches!(
self,
Self::Int
| Self::Float
| Self::Bool
| Self::Byte
| Self::String
| Self::Array
| Self::Name
| Self::Object
| Self::Function
| Self::State
| Self::Delegate
)
}
}