rott/rottlib/src/ast/operators.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

269 lines
8.4 KiB
Rust

//! Operator AST nodes.
//!
//! This module defines the prefix, postfix, and infix operator kinds used by
//! expression AST nodes.
//!
//! The enums here represent only the *syntactic operator category* recorded in
//! the AST. They do not encode precedence, associativity, overload behavior,
//! or token spelling details beyond the normalized operator kind itself.
//! Those concerns are handled by the expression parser and precedence tables.
use crate::lexer::{Keyword, Token, TokenPosition};
use core::convert::TryFrom;
/// Prefix unary operators.
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum PrefixOperator {
/// Logical negation: `!expr`.
Not,
/// Arithmetic negation: `-expr`.
Minus,
/// Unary plus: `+expr`.
Plus,
/// Bitwise negation: `~expr`.
BitwiseNot,
/// Prefix increment: `++expr`.
Increment,
/// Prefix decrement: `--expr`.
Decrement,
}
/// Postfix unary operators.
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum PostfixOperator {
/// Postfix increment: `expr++`.
Increment,
/// Postfix decrement: `expr--`.
Decrement,
}
/// Binary / infix operators.
///
/// These operators appear between left-hand side and right-hand side operands.
/// This enum stores only the normalized AST-level operator kind.
///
/// The parser assigns precedence and associativity separately.
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum InfixOperator {
/// Simple assignment: `left_hand_side = right_hand_side`.
Assign,
/// Multiplicative assignment: `left_hand_side *= right_hand_side`.
MultiplyAssign,
/// Division assignment: `left_hand_side /= right_hand_side`.
DivideAssign,
/// Modulo assignment: `left_hand_side %= right_hand_side`.
ModuloAssign,
/// Additive assignment: `left_hand_side += right_hand_side`.
PlusAssign,
/// Subtractive assignment: `left_hand_side -= right_hand_side`.
MinusAssign,
/// String concatenation assignment: `left_hand_side $= right_hand_side`.
ConcatAssign,
/// Space-concatenation assignment: `left_hand_side @= right_hand_side`.
ConcatSpaceAssign,
/// String concatenation without inserted whitespace:
/// `left_hand_side $ right_hand_side`.
Concat,
/// String concatenation with an inserted space:
/// `left_hand_side @ right_hand_side`.
ConcatSpace,
/// Logical conjunction: `left_hand_side && right_hand_side`.
And,
/// Logical exclusive-or: `left_hand_side ^^ right_hand_side`.
Xor,
/// Logical disjunction: `left_hand_side || right_hand_side`.
Or,
/// Bitwise AND: `left_hand_side & right_hand_side`.
BitwiseAnd,
/// Bitwise OR: `left_hand_side | right_hand_side`.
BitwiseOr,
/// Bitwise XOR: `left_hand_side ^ right_hand_side`.
BitwiseXor,
/// Inequality test: `left_hand_side != right_hand_side`.
NotEqual,
/// Equality test: `left_hand_side == right_hand_side`.
Equal,
/// Approximate equality test: `left_hand_side ~= right_hand_side`.
ApproximatelyEqual,
/// Less-than comparison: `left_hand_side < right_hand_side`.
Less,
/// Less-than-or-equal comparison: `left_hand_side <= right_hand_side`.
LessEqual,
/// Greater-than comparison: `left_hand_side > right_hand_side`.
Greater,
/// Greater-than-or-equal comparison: `left_hand_side >= right_hand_side`.
GreaterEqual,
/// UnrealScript-specific directional comparison:
/// `left_hand_side ClockwiseFrom right_hand_side`.
ClockwiseFrom,
/// Left shift: `left_hand_side << right_hand_side`.
LeftShift,
/// Logical right shift: `left_hand_side >>> right_hand_side`.
LogicalRightShift,
/// Arithmetic / ordinary right shift: `left_hand_side >> right_hand_side`.
RightShift,
/// Addition: `left_hand_side + right_hand_side`.
Plus,
/// Subtraction: `left_hand_side - right_hand_side`.
Minus,
/// Remainder / modulo: `left_hand_side % right_hand_side`.
Modulo,
/// Multiplication: `left_hand_side * right_hand_side`.
Multiply,
/// Division: `left_hand_side / right_hand_side`.
Divide,
/// Dot product: `left_hand_side Dot right_hand_side`.
///
/// This is spelled as a keyword-level operator in source.
Dot,
/// Cross product: `left_hand_side Cross right_hand_side`.
///
/// This is spelled as a keyword-level operator in source.
Cross,
/// Exponentiation: `left_hand_side ** right_hand_side`.
Exponentiation,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PrefixOperatorName {
pub kind: PrefixOperator,
pub position: TokenPosition,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InfixOperatorName {
pub kind: InfixOperator,
pub position: TokenPosition,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PostfixOperatorName {
pub kind: PostfixOperator,
pub position: TokenPosition,
}
impl TryFrom<Token> for PostfixOperator {
type Error = ();
fn try_from(token: Token) -> Result<Self, Self::Error> {
use PostfixOperator::{Decrement, Increment};
match token {
Token::Increment => Ok(Increment),
Token::Decrement => Ok(Decrement),
_ => Err(()),
}
}
}
impl TryFrom<Token> for PrefixOperator {
type Error = ();
fn try_from(token: Token) -> Result<Self, Self::Error> {
use PrefixOperator::{BitwiseNot, Decrement, Increment, Minus, Not, Plus};
match token {
Token::Not => Ok(Not),
Token::Minus => Ok(Minus),
Token::Plus => Ok(Plus),
Token::BitwiseNot => Ok(BitwiseNot),
Token::Increment => Ok(Increment),
Token::Decrement => Ok(Decrement),
_ => Err(()),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct InfixOperatorInfo {
pub operator: InfixOperator,
pub right_precedence_rank: u8,
}
pub(crate) const fn infix_operator_info(token: Token) -> Option<InfixOperatorInfo> {
use InfixOperator::{
And, ApproximatelyEqual, Assign, BitwiseAnd, BitwiseOr, BitwiseXor, ClockwiseFrom, Concat,
ConcatAssign, ConcatSpace, ConcatSpaceAssign, Cross, Divide, DivideAssign, Dot, Equal,
Exponentiation, Greater, GreaterEqual, LeftShift, Less, LessEqual, LogicalRightShift,
Minus, MinusAssign, Modulo, ModuloAssign, Multiply, MultiplyAssign, NotEqual, Or, Plus,
PlusAssign, RightShift, Xor,
};
let (precedence_rank, operator) = match token {
Token::Exponentiation => (12, Exponentiation),
Token::Multiply => (16, Multiply),
Token::Divide => (16, Divide),
Token::Keyword(Keyword::Cross) => (16, Cross),
Token::Keyword(Keyword::Dot) => (16, Dot),
Token::Modulo => (18, Modulo),
Token::Plus => (20, Plus),
Token::Minus => (20, Minus),
Token::LeftShift => (22, LeftShift),
Token::RightShift => (22, RightShift),
Token::LogicalRightShift => (22, LogicalRightShift),
Token::Less => (24, Less),
Token::LessEqual => (24, LessEqual),
Token::Greater => (24, Greater),
Token::GreaterEqual => (24, GreaterEqual),
Token::Equal => (24, Equal),
Token::ApproximatelyEqual => (24, ApproximatelyEqual),
Token::Keyword(Keyword::ClockwiseFrom) => (24, ClockwiseFrom),
Token::NotEqual => (26, NotEqual),
Token::BitwiseAnd => (28, BitwiseAnd),
Token::BitwiseXor => (28, BitwiseXor),
Token::BitwiseOr => (28, BitwiseOr),
Token::LogicalAnd => (30, And),
Token::LogicalXor => (30, Xor),
Token::LogicalOr => (32, Or),
Token::MultiplyAssign => (34, MultiplyAssign),
Token::DivideAssign => (34, DivideAssign),
Token::PlusAssign => (34, PlusAssign),
Token::MinusAssign => (34, MinusAssign),
Token::Assign => (34, Assign),
Token::ModuloAssign => (34, ModuloAssign),
Token::Concat => (40, Concat),
Token::ConcatSpace => (40, ConcatSpace),
Token::ConcatAssign => (44, ConcatAssign),
Token::ConcatSpaceAssign => (44, ConcatSpaceAssign),
_ => return None,
};
Some(InfixOperatorInfo {
operator,
right_precedence_rank: precedence_rank,
})
}
impl TryFrom<Token> for InfixOperator {
type Error = ();
fn try_from(token: Token) -> Result<Self, Self::Error> {
infix_operator_info(token)
.map(|info| info.operator)
.ok_or(())
}
}