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.
269 lines
8.4 KiB
Rust
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(())
|
|
}
|
|
}
|